Doctrine2 - Trigger event on property change (PropertyChangeListener)

天大地大妈咪最大 提交于 2019-12-13 17:39:55

问题


I am not writing "what did I try" or "what is not working" since I can think of many ways to implement something like this. But I cannot believe that no one did something similar before and that is why I would like to ask the question to see what kind of Doctrine2 best practices show up.


What I want is to trigger an event on a property change. So let's say I have an entity with an $active property and I want a EntityBecameActive event to fire for each entity when the property changes from false to true.

Other libraries often have a PropertyChanged event but there is no such thing available in Doctrine2.

So I have some entity like this:

<?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;
    }
}

回答1:


Maybe ChangeTracking Policy is what you want, maybe it is not!

The NOTIFY policy is based on the assumption that the entities notify interested listeners of changes to their properties. For that purpose, a class that wants to use this policy needs to implement the NotifyPropertyChanged interface from the Doctrine\Common namespace.

Check full example in link above.

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;
        }
    }
}

UPDATE


This is a full example but silly one so you can work on it as you wish. It just demonstrates how you do it, so don't take it too serious!

entity

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;
    }
}

domainobject

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());
            }
        }
    }
}

controller

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();
    }
}

And have this file with 777 permissions (again, this is test) to it: src/Football/TeamBundle/Entity/log.txt

When you run the code, your log file will have timestamp stored in it, just for demonstration purposes.



来源:https://stackoverflow.com/questions/31179323/doctrine2-trigger-event-on-property-change-propertychangelistener

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!