我应该使用什么事件来检测实体再次持久但不会被更改?

时间:2016-05-18 21:42:04

标签: doctrine symfony

我想在更新实体时触发事件,即使数据没有改变。那么,我应该使用什么事件?

提醒:我想访问实体数据,因此我无法使用onFlush。此外,由于实体数据未被更改,因此不会触发preUpatepostUpdate

Doctrine events docs

2 个答案:

答案 0 :(得分:0)

您可以在服务管理器中集中实体的持久性。 在这位经理中尝试派遣一般事件

use Symfony\Component\EventDispatcher\GenericEvent;
...
...
    public function persistAndFlush($entity)
    {
        $this->em->persist($entity);
        $this->em->flush();

        //dispatch an event
        $event = new GenericEvent($entity, array('course_history' => 1));
        $this->dispatcher->dispatch(YourClassEvents::UPDATE_ENTITY, $event);
    }

然后你可以创建一个列表器来监听这个通用事件

修改

更多详情

假设我们有实体产品

namespace Domain\YourBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

class Product
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string $productName
     *
     * @ORM\Column(name="productName", type="string", length=255, nullable=false)
     */
    private $productName;
    ...
    ...
    ...
    //setters and getters
}
  • 创建服务管理器
  

service.xml中

<service id="yourdomain.product_manager" class="Domain\YourBundle\Service\ProductManager">
    <argument type="service" id="doctrine.orm.entity_manager"/>
    <argument type="service" id="event_dispatcher"/>
</service>
  • 创建我们的经理
  

ProductManager类

namespace Domain\YourBundle\Manager;

use Doctrine\ORM\EntityManager;
use Domain\YourBundle\Entity\Product;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;

class ProductManager
{
    /**
     * @var EntityManager
     */
    protected $em;
    /**
     * @var EventDispatcherInterface
     */
    protected $dispatcher;
    /**
     * @param EntityManager $em
     */
    public function __construct(EntityManager $em, EventDispatcherInterface $dispatcher)
    {
        $this->em = $em;
        $this->dispatcher = $dispatcher;
    }

    public function persistAndFlush($product)
    {
        $this->em->persist($product);
        $this->em->flush();

        //The entity is updated then dispatch an event 
        $event = new GenericEvent($product, array('product_name' => 1));
        $this->dispatcher->dispatch('product', $event);
    }
}
  

在service.xml中添加listener的定义

<service id="yourdomain.event.update_product" class="Domain\YourBundle\EventListener\UpdateProductListener">

    <argument type="service" id="logger"/>
    <tag name="kernel.event_listener" event="product" method="onUpdateProduct"/>
</service>
  

类UpdateProductListener

namespace Domain\YourBundle\EventListener;

use Symfony\Component\EventDispatcher\GenericEvent;
use Domain\YourBundle\Entity\Product;
use Psr\Log\LoggerInterface;

class UpdateProductListener
{
    private $logger;

    /**
     * @param LoggerInterface $logger
     */
    public function __construct(LoggerInterface $logger) {
        $this->logger = $logger;
    }
    /**
     * Listen the generic event dispatched when the product name is updated
     *
     * @param GenericEvent $event
     *
     * @throws RuntimeException
     * @throws \ErrorException
     */
    public function onUpdateProduct(GenericEvent $event)
    {
        if ($event->getSubject() instanceof Product) {
            $product = $event->getSubject();

            if ($event->hasArgument('product_name') && $event->getArgument('product_name') == 1) {
                /*
                Make your logic (send mail, add log, notification....)
                */
                $this->logger->notice('UpdateProductListener : event update product is occured');

            } else {
                $this->logger->notice('UpdateProductListener : event other than update product is occured.');
            }
        }
    }
}

答案 1 :(得分:0)

我在这里看到了问题。您希望在更新后访问实体,但实体不是真正的更新。所以你显然在这里使用DQL查询,正如你正确提到的this disallows you to access pre\postUpdate。问题是,学说并不真正知道对象已被更改 - 查询可能有点复杂,因此可以隐藏对象标识符。甚至不知道(在MySQL的情况下)

某些RDBM具有RETURNING子句,允许您查看更新结果,但它不是DB摘要,因此无法从开箱即用的DQL访问。

您可以使用本机SQL查询或执行其他技巧来获取更新的行。

如果查询不是性能关键,我宁愿建议用一些软件(php-side)处理简单的doctrine flush。

如果是 - 我认为这是不可能的。如果您对用例提供更多详细信息,可以讨论解决方法。

即。您可以使用versioning迭代EM处缓存的所有实体,并检查vesrion是否已更改。