【问题标题】:Doctrine2 - Trigger event on property change (PropertyChangeListener)Doctrine2 - 属性更改触发事件 (PropertyChangeListener)
【发布时间】:2015-07-02 08:27:05
【问题描述】:

我不是在写“我尝试了什么”或“什么不起作用”,因为我可以想出很多方法来实现这样的事情。但我不敢相信以前没有人做过类似的事情,这就是为什么我想问这个问题,看看出现了什么样的 Doctrine2 最佳实践。


我想要的是在属性更改时触发事件。因此,假设我有一个具有$active 属性的实体,并且我希望在属性从false 更改为true 时为每个实体触发一个EntityBecameActive 事件。

其他库通常有 PropertyChanged 事件,但在 Doctrine2 中没有这样的可用。

所以我有一些这样的实体:

<?php

namespace Application\Entity;

class Entity
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\Column(type="integer");
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @var boolean
     * @ORM\Column(type="boolean", nullable=false)
     */
    protected $active = false;

    /**
     * Get active.
     *
     * @return string
     */
    public function getActive()
    {
        return $this->active;
    }

    /**
     * Is active.
     *
     * @return string
     */
    public function isActive()
    {
        return $this->active;
    }

    /**
     * Set active.
     *
     * @param bool $active
     * @return self
     */
    public function setActive($active)
    {
        $this->active = $active;
        return $this;
    }
}

【问题讨论】:

    标签: php events doctrine-orm eventtrigger propertychangelistener


    【解决方案1】:

    也许ChangeTracking政策是你想要的,也许不是!

    NOTIFY 政策基于实体通知的假设 对其属性的更改感兴趣的听众。为了这个目的, 想要使用此策略的类需要实现 来自 Doctrine\Common 命名空间的 NotifyPropertyChanged 接口。

    查看上面链接中的完整示例。

    class MyEntity extends DomainObject
    {
        private $data;
        // ... other fields as usual
    
        public function setData($data) {
            if ($data != $this->data) { // check: is it actually modified?
                $this->onPropertyChanged('data', $this->data, $data);
                $this->data = $data;
            }
        }
    }
    

    更新


    这是一个完整的示例,但很愚蠢,因此您可以根据需要进行处理。它只是展示了你是如何做到的,所以不要太认真!

    实体

    namespace Football\TeamBundle\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity
     * @ORM\Table(name="country")
     */
    class Country extends DomainObject
    {
        /**
         * @var int
         *
         * @ORM\Id
         * @ORM\Column(type="smallint")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;
    
        /**
         * @var string
         *
         * @ORM\Column(type="string", length=2, unique=true)
         */
        protected $code;
    
        /**
         * Get id
         *
         * @return integer
         */
        public function getId()
        {
            return $this->id;
        }
    
        /**
         * Set code
         *
         * @param string $code
         * @return Country
         */
        public function setCode($code)
        {
            if ($code != $this->code) {
                $this->onPropertyChanged('code', $this->code, $code);
                $this->code = $code;
            }
    
            return $this;
        }
    
        /**
         * Get code
         *
         * @return string
         */
        public function getCode()
        {
            return $this->code;
        }
    }
    

    域对象

    namespace Football\TeamBundle\Entity;
    
    use Doctrine\Common\NotifyPropertyChanged;
    use Doctrine\Common\PropertyChangedListener;
    
    abstract class DomainObject implements NotifyPropertyChanged
    {
        private $listeners = array();
    
        public function addPropertyChangedListener(PropertyChangedListener $listener)
        {
            $this->listeners[] = $listener;
        }
    
        protected function onPropertyChanged($propName, $oldValue, $newValue)
        {
            $filename = '../src/Football/TeamBundle/Entity/log.txt';
            $content = file_get_contents($filename);
    
            if ($this->listeners) {
                foreach ($this->listeners as $listener) {
                    $listener->propertyChanged($this, $propName, $oldValue, $newValue);
    
                    file_put_contents($filename, $content . "\n" . time());
                }
            }
        }
    }
    

    控制器

    namespace Football\TeamBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Football\TeamBundle\Entity\Country;
    
    class DefaultController extends Controller
    {
        public function indexAction()
        {
            // First run this to create or just manually punt in DB
            $this->createAction('AB');
            // Run this to update it
            $this->updateAction('AB');
    
            return $this->render('FootballTeamBundle:Default:index.html.twig', array('name' => 'inanzzz'));
        }
    
        public function createAction($code)
        {
            $em = $this->getDoctrine()->getManager();
            $country = new Country();
            $country->setCode($code);
            $em->persist($country);
            $em->flush();
        }
    
        public function updateAction($code)
        {
            $repo = $this->getDoctrine()->getRepository('FootballTeamBundle:Country');
            $country = $repo->findOneBy(array('code' => $code));
            $country->setCode('BB');
    
            $em = $this->getDoctrine()->getManager();
            $em->flush();
        }
    }
    

    并让这个文件拥有 777 权限(同样,这是测试):src/Football/TeamBundle/Entity/log.txt

    当您运行代码时,您的日志文件中将存储时间戳,仅用于演示目的。

    【讨论】:

    • 这看起来确实很有趣,我会深入研究文档:)
    • 我使用它的原因和你的一样,所以看看它是否满足你的确切需求。
    • 你只是在构造函数中添加监听器吗?
    • 我也不喜欢我的实体被额外的代码臃肿,所以我认为你最好使用Entity Listener
    猜你喜欢
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多