Event listener to programmatically attach entity listeners.
This commit is contained in:
parent
3529cd4282
commit
e69cd37226
@ -2510,7 +2510,11 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
*/
|
||||
public function addEntityListener($eventName, $class, $method)
|
||||
{
|
||||
$class = $this->fullyQualifiedClassName($class);
|
||||
$class = $this->fullyQualifiedClassName($class);
|
||||
$listener = array(
|
||||
'class' => $class,
|
||||
'method' => $method
|
||||
);
|
||||
|
||||
if ( ! class_exists($class)) {
|
||||
throw MappingException::entityListenerClassNotFound($class, $this->name);
|
||||
@ -2520,10 +2524,11 @@ class ClassMetadataInfo implements ClassMetadata
|
||||
throw MappingException::entityListenerMethodNotFound($class, $method, $this->name);
|
||||
}
|
||||
|
||||
$this->entityListeners[$eventName][] = array(
|
||||
'class' => $class,
|
||||
'method' => $method
|
||||
);
|
||||
if (isset($this->entityListeners[$eventName]) && in_array($listener, $this->entityListeners[$eventName])) {
|
||||
throw MappingException::duplicateEntityListener($class, $method, $this->name);
|
||||
}
|
||||
|
||||
$this->entityListeners[$eventName][] = $listener;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -707,6 +707,18 @@ class MappingException extends \Doctrine\ORM\ORMException
|
||||
return new self(sprintf('Entity Listener "%s" declared on "%s" has no method "%s".', $listenerName, $className, $methodName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $listenerName
|
||||
* @param string $methodName
|
||||
* @param string $className
|
||||
*
|
||||
* @return \Doctrine\ORM\Mapping\MappingException
|
||||
*/
|
||||
public static function duplicateEntityListener($listenerName, $methodName, $className)
|
||||
{
|
||||
return new self(sprintf('Entity Listener "%s#%s()" in "%s" was already declared, but it must be declared only once.', $listenerName, $methodName, $className));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $annotation
|
||||
|
79
lib/Doctrine/ORM/Tools/AttachEntityListenersListener.php
Normal file
79
lib/Doctrine/ORM/Tools/AttachEntityListenersListener.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Tools;
|
||||
|
||||
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||
|
||||
/**
|
||||
* Mechanism to programmatically attach entity listeners.
|
||||
*
|
||||
* @author Fabio B. SIlva <fabio.bat.silva@gmail.com>
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
class AttachEntityListenersListener
|
||||
{
|
||||
/**
|
||||
* @var array[]
|
||||
*/
|
||||
private $entityListeners = array();
|
||||
|
||||
/**
|
||||
* Adds a entity listener for a specific entity.
|
||||
*
|
||||
* @param string $entityClass The entity to attach the listener.
|
||||
* @param string $listenerClass The listener class.
|
||||
* @param string $eventName The entity lifecycle event.
|
||||
* @param string $listenerCallback|null The listener callback method or NULL to use $eventName.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addEntityListener($entityClass, $listenerClass, $eventName, $listenerCallback = null)
|
||||
{
|
||||
$this->entityListeners[ltrim($entityClass, '\\')][] = array(
|
||||
'event' => $eventName,
|
||||
'class' => $listenerClass,
|
||||
'method' => $listenerCallback ?: $eventName
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes event and attach the entity listener.
|
||||
*
|
||||
* @param \Doctrine\ORM\Event\LoadClassMetadataEventArgs $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function loadClassMetadata(LoadClassMetadataEventArgs $event)
|
||||
{
|
||||
/** @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */
|
||||
$metadata = $event->getClassMetadata();
|
||||
|
||||
if ( ! isset($this->entityListeners[$metadata->name])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->entityListeners[$metadata->name] as $listener) {
|
||||
$metadata->addEntityListener($listener['event'], $listener['class'], $listener['method']);
|
||||
}
|
||||
|
||||
unset($this->entityListeners[$metadata->name]);
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools;
|
||||
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\Tests\OrmTestCase;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\ORM\Tools\AttachEntityListenersListener;
|
||||
|
||||
class AttachEntityListenersListenerTest extends OrmTestCase
|
||||
{
|
||||
/**
|
||||
* @var \Doctrine\ORM\EntityManager
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Tools\AttachEntityListenersListener
|
||||
*/
|
||||
private $listener;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\ORM\Mapping\ClassMetadataFactory
|
||||
*/
|
||||
private $factory;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->listener = new AttachEntityListenersListener();
|
||||
$driver = $this->createAnnotationDriver();
|
||||
$this->em = $this->_getTestEntityManager();
|
||||
$evm = $this->em->getEventManager();
|
||||
$this->factory = new ClassMetadataFactory;
|
||||
|
||||
$evm->addEventListener(Events::loadClassMetadata, $this->listener);
|
||||
$this->em->getConfiguration()->setMetadataDriverImpl($driver);
|
||||
$this->factory->setEntityManager($this->em);
|
||||
}
|
||||
|
||||
public function testAttachEntityListeners()
|
||||
{
|
||||
$this->listener->addEntityListener(
|
||||
AttachEntityListenersListenerTestFooEntity::CLASSNAME,
|
||||
AttachEntityListenersListenerTestListener::CLASSNAME,
|
||||
Events::postLoad,
|
||||
'postLoadHandler'
|
||||
);
|
||||
|
||||
$metadata = $this->factory->getMetadataFor(AttachEntityListenersListenerTestFooEntity::CLASSNAME);
|
||||
|
||||
$this->assertArrayHasKey('postLoad', $metadata->entityListeners);
|
||||
$this->assertCount(1, $metadata->entityListeners['postLoad']);
|
||||
$this->assertEquals('postLoadHandler', $metadata->entityListeners['postLoad'][0]['method']);
|
||||
$this->assertEquals(AttachEntityListenersListenerTestListener::CLASSNAME, $metadata->entityListeners['postLoad'][0]['class']);
|
||||
}
|
||||
|
||||
public function testAttachToExistingEntityListeners()
|
||||
{
|
||||
$this->listener->addEntityListener(
|
||||
AttachEntityListenersListenerTestBarEntity::CLASSNAME,
|
||||
AttachEntityListenersListenerTestListener2::CLASSNAME,
|
||||
Events::prePersist
|
||||
);
|
||||
|
||||
$this->listener->addEntityListener(
|
||||
AttachEntityListenersListenerTestBarEntity::CLASSNAME,
|
||||
AttachEntityListenersListenerTestListener2::CLASSNAME,
|
||||
Events::postPersist,
|
||||
'postPersistHandler'
|
||||
);
|
||||
|
||||
$metadata = $this->factory->getMetadataFor(AttachEntityListenersListenerTestBarEntity::CLASSNAME);
|
||||
|
||||
$this->assertArrayHasKey('postPersist', $metadata->entityListeners);
|
||||
$this->assertArrayHasKey('prePersist', $metadata->entityListeners);
|
||||
|
||||
$this->assertCount(2, $metadata->entityListeners['prePersist']);
|
||||
$this->assertCount(2, $metadata->entityListeners['postPersist']);
|
||||
|
||||
$this->assertEquals('prePersist', $metadata->entityListeners['prePersist'][0]['method']);
|
||||
$this->assertEquals(AttachEntityListenersListenerTestListener::CLASSNAME, $metadata->entityListeners['prePersist'][0]['class']);
|
||||
|
||||
$this->assertEquals('prePersist', $metadata->entityListeners['prePersist'][1]['method']);
|
||||
$this->assertEquals(AttachEntityListenersListenerTestListener2::CLASSNAME, $metadata->entityListeners['prePersist'][1]['class']);
|
||||
|
||||
$this->assertEquals('postPersist', $metadata->entityListeners['postPersist'][0]['method']);
|
||||
$this->assertEquals(AttachEntityListenersListenerTestListener::CLASSNAME, $metadata->entityListeners['postPersist'][0]['class']);
|
||||
|
||||
$this->assertEquals('postPersistHandler', $metadata->entityListeners['postPersist'][1]['method']);
|
||||
$this->assertEquals(AttachEntityListenersListenerTestListener2::CLASSNAME, $metadata->entityListeners['postPersist'][1]['class']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Doctrine\ORM\Mapping\MappingException
|
||||
* @expectedExceptionMessage Entity Listener "Doctrine\Tests\ORM\Tools\AttachEntityListenersListenerTestListener#postPersist()" in "Doctrine\Tests\ORM\Tools\AttachEntityListenersListenerTestFooEntity" was already declared, but it must be declared only once.
|
||||
*/
|
||||
public function testDuplicateEntityListenerException()
|
||||
{
|
||||
$this->listener->addEntityListener(
|
||||
AttachEntityListenersListenerTestFooEntity::CLASSNAME,
|
||||
AttachEntityListenersListenerTestListener::CLASSNAME,
|
||||
Events::postPersist
|
||||
);
|
||||
|
||||
$this->listener->addEntityListener(
|
||||
AttachEntityListenersListenerTestFooEntity::CLASSNAME,
|
||||
AttachEntityListenersListenerTestListener::CLASSNAME,
|
||||
Events::postPersist
|
||||
);
|
||||
|
||||
$this->factory->getMetadataFor(AttachEntityListenersListenerTestFooEntity::CLASSNAME);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
*/
|
||||
class AttachEntityListenersListenerTestFooEntity
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Entity
|
||||
* @EntityListeners({"AttachEntityListenersListenerTestListener"})
|
||||
*/
|
||||
class AttachEntityListenersListenerTestBarEntity
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
/**
|
||||
* @Id
|
||||
* @Column(type="integer")
|
||||
* @GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
public $id;
|
||||
}
|
||||
|
||||
class AttachEntityListenersListenerTestListener
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
public $calls;
|
||||
|
||||
public function prePersist()
|
||||
{
|
||||
$this->calls[__FUNCTION__][] = func_get_args();
|
||||
}
|
||||
|
||||
public function postLoadHandler()
|
||||
{
|
||||
$this->calls[__FUNCTION__][] = func_get_args();
|
||||
}
|
||||
|
||||
public function postPersist()
|
||||
{
|
||||
$this->calls[__FUNCTION__][] = func_get_args();
|
||||
}
|
||||
}
|
||||
|
||||
class AttachEntityListenersListenerTestListener2
|
||||
{
|
||||
const CLASSNAME = __CLASS__;
|
||||
|
||||
public $calls;
|
||||
|
||||
public function prePersist()
|
||||
{
|
||||
$this->calls[__FUNCTION__][] = func_get_args();
|
||||
}
|
||||
|
||||
public function postPersistHandler()
|
||||
{
|
||||
$this->calls[__FUNCTION__][] = func_get_args();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user