From e6d9d1de47ff5a085e84d73dc3738bfecef2ab5f Mon Sep 17 00:00:00 2001 From: "Fabio B. Silva" Date: Wed, 5 Dec 2012 18:47:48 -0200 Subject: [PATCH] support naming convention for listeners without mapping. --- .../ORM/Mapping/Driver/AnnotationDriver.php | 13 ++++- lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php | 10 +++- .../ORM/Mapping/Driver/YamlDriver.php | 8 +++ .../Doctrine/Tests/Models/CMS/CmsAddress.php | 18 ++++-- .../Tests/Models/CMS/CmsAddressListener.php | 58 +++++++++++++++++++ .../ORM/Mapping/AbstractMappingDriverTest.php | 57 ++++++++++++++++++ .../Doctrine.Tests.Models.CMS.CmsAddress.php | 16 ++++- ...ctrine.Tests.Models.CMS.CmsAddress.dcm.xml | 4 ++ ...ctrine.Tests.Models.CMS.CmsAddress.dcm.yml | 2 + 9 files changed, 175 insertions(+), 11 deletions(-) create mode 100644 tests/Doctrine/Tests/Models/CMS/CmsAddressListener.php diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index a5c01fedb..a4bea98ea 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -23,6 +23,7 @@ use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\ORM\Mapping\MappingException; use Doctrine\ORM\Mapping\JoinColumn; use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder; use Doctrine\Common\Persistence\Mapping\ClassMetadata; use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver; use Doctrine\ORM\Events; @@ -426,14 +427,22 @@ class AnnotationDriver extends AbstractAnnotationDriver throw MappingException::entityListenerClassNotFound($listenerClassName, $className); } - $listenerClass = new \ReflectionClass($listenerClassName); + $hasMapping = false; + $listenerClass = new \ReflectionClass($listenerClassName); /* @var $method \ReflectionMethod */ foreach ($listenerClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { // find method callbacks. - foreach ($this->getMethodCallbacks($method) as $value) { + $callbacks = $this->getMethodCallbacks($method); + $hasMapping = $hasMapping ?: ( ! empty($callbacks)); + + foreach ($callbacks as $value) { $metadata->addEntityListener($value[1], $listenerClassName, $value[0]); } } + // Evaluate the listener using naming convention. + if ( ! $hasMapping ) { + EntityListenerBuilder::bindEntityListener($metadata, $listenerClassName); + } } } diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php index 625940d6d..26d1becd0 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -21,6 +21,7 @@ namespace Doctrine\ORM\Mapping\Driver; use SimpleXMLElement; use Doctrine\Common\Persistence\Mapping\Driver\FileDriver; +use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder; use Doctrine\Common\Persistence\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\MappingException; @@ -560,10 +561,17 @@ class XmlDriver extends FileDriver // Evaluate entity listener if (isset($xmlRoot->{'entity-listeners'})) { foreach ($xmlRoot->{'entity-listeners'}->{'entity-listener'} as $listenerElement) { + $className = (string) $listenerElement['class']; + // Evaluate the listener using naming convention. + if($listenerElement->count() === 0) { + EntityListenerBuilder::bindEntityListener($metadata, $className); + + continue; + } + foreach ($listenerElement as $callbackElement) { $eventName = (string) $callbackElement['type']; $methodName = (string) $callbackElement['method']; - $className = (string) $listenerElement['class']; $metadata->addEntityListener($eventName, $className, $methodName); } diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index e53de341c..bf97f19fb 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -20,6 +20,7 @@ namespace Doctrine\ORM\Mapping\Driver; use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder; use Doctrine\Common\Persistence\Mapping\Driver\FileDriver; use Doctrine\ORM\Mapping\MappingException; use Symfony\Component\Yaml\Yaml; @@ -576,6 +577,13 @@ class YamlDriver extends FileDriver // Evaluate entityListeners if (isset($element['entityListeners'])) { foreach ($element['entityListeners'] as $className => $entityListener) { + // Evaluate the listener using naming convention. + if (empty($entityListener)) { + EntityListenerBuilder::bindEntityListener($metadata, $className); + + continue; + } + foreach ($entityListener as $eventName => $callbackElement){ foreach ($callbackElement as $methodName){ $metadata->addEntityListener($eventName, $className, $methodName); diff --git a/tests/Doctrine/Tests/Models/CMS/CmsAddress.php b/tests/Doctrine/Tests/Models/CMS/CmsAddress.php index 7d22275b2..aaf4956d3 100644 --- a/tests/Doctrine/Tests/Models/CMS/CmsAddress.php +++ b/tests/Doctrine/Tests/Models/CMS/CmsAddress.php @@ -59,6 +59,7 @@ namespace Doctrine\Tests\Models\CMS; * ) * }) * + * @EntityListeners({"CmsAddressListener"}) */ class CmsAddress { @@ -94,11 +95,6 @@ class CmsAddress */ public $user; - /** - * @var array - */ - public $prePersistHandlerCalls = array(); - public function getId() { return $this->id; } @@ -213,5 +209,17 @@ class CmsAddress ), ) )); + + $metadata->addEntityListener(\Doctrine\ORM\Events::postPersist, 'CmsAddressListener', 'postPersist'); + $metadata->addEntityListener(\Doctrine\ORM\Events::prePersist, 'CmsAddressListener', 'prePersist'); + + $metadata->addEntityListener(\Doctrine\ORM\Events::postUpdate, 'CmsAddressListener', 'postUpdate'); + $metadata->addEntityListener(\Doctrine\ORM\Events::preUpdate, 'CmsAddressListener', 'preUpdate'); + + $metadata->addEntityListener(\Doctrine\ORM\Events::postRemove, 'CmsAddressListener', 'postRemove'); + $metadata->addEntityListener(\Doctrine\ORM\Events::preRemove, 'CmsAddressListener', 'preRemove'); + + $metadata->addEntityListener(\Doctrine\ORM\Events::preFlush, 'CmsAddressListener', 'preFlush'); + $metadata->addEntityListener(\Doctrine\ORM\Events::postLoad, 'CmsAddressListener', 'postLoad'); } } \ No newline at end of file diff --git a/tests/Doctrine/Tests/Models/CMS/CmsAddressListener.php b/tests/Doctrine/Tests/Models/CMS/CmsAddressListener.php new file mode 100644 index 000000000..9c9db89eb --- /dev/null +++ b/tests/Doctrine/Tests/Models/CMS/CmsAddressListener.php @@ -0,0 +1,58 @@ +calls[__FUNCTION__][] = func_get_args(); + } + + public function postPersist() + { + $this->calls[__FUNCTION__][] = func_get_args(); + } + + public function preUpdate() + { + $this->calls[__FUNCTION__][] = func_get_args(); + } + + public function postUpdate() + { + $this->calls[__FUNCTION__][] = func_get_args(); + } + + public function preRemove() + { + $this->calls[__FUNCTION__][] = func_get_args(); + } + + public function postRemove() + { + $this->calls[__FUNCTION__][] = func_get_args(); + } + + public function postLoad() + { + $this->calls[__FUNCTION__][] = func_get_args(); + } + + public function preFlush() + { + $this->calls[__FUNCTION__][] = func_get_args(); + } + + protected function postPersistHandler() + { + throw new \BadMethodCallException("This is not a valid callback"); + } + + protected function prePersistHandler() + { + throw new \BadMethodCallException("This is not a valid callback"); + } +} \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index bfbab9e32..24b72aaa3 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -814,6 +814,63 @@ abstract class AbstractMappingDriverTest extends \Doctrine\Tests\OrmTestCase $this->assertEquals('Doctrine\Tests\Models\Company\CompanyFlexUltraContractListener', $prePersist['class']); $this->assertEquals('prePersistHandler2', $prePersist['method']); } + + + /** + * @group DDC-1955 + */ + public function testEntityListenersNamingConvention() + { + $em = $this->_getTestEntityManager(); + $factory = $this->createClassMetadataFactory($em); + $metadata = $factory->getMetadataFor('Doctrine\Tests\Models\CMS\CmsAddress'); + + $this->assertArrayHasKey(Events::postPersist, $metadata->entityListeners); + $this->assertArrayHasKey(Events::prePersist, $metadata->entityListeners); + $this->assertArrayHasKey(Events::postUpdate, $metadata->entityListeners); + $this->assertArrayHasKey(Events::preUpdate, $metadata->entityListeners); + $this->assertArrayHasKey(Events::postRemove, $metadata->entityListeners); + $this->assertArrayHasKey(Events::preRemove, $metadata->entityListeners); + $this->assertArrayHasKey(Events::postLoad, $metadata->entityListeners); + $this->assertArrayHasKey(Events::preFlush, $metadata->entityListeners); + + $this->assertCount(1, $metadata->entityListeners[Events::postPersist]); + $this->assertCount(1, $metadata->entityListeners[Events::prePersist]); + $this->assertCount(1, $metadata->entityListeners[Events::postUpdate]); + $this->assertCount(1, $metadata->entityListeners[Events::preUpdate]); + $this->assertCount(1, $metadata->entityListeners[Events::postRemove]); + $this->assertCount(1, $metadata->entityListeners[Events::preRemove]); + $this->assertCount(1, $metadata->entityListeners[Events::postLoad]); + $this->assertCount(1, $metadata->entityListeners[Events::preFlush]); + + $postPersist = $metadata->entityListeners[Events::postPersist][0]; + $prePersist = $metadata->entityListeners[Events::prePersist][0]; + $postUpdate = $metadata->entityListeners[Events::postUpdate][0]; + $preUpdate = $metadata->entityListeners[Events::preUpdate][0]; + $postRemove = $metadata->entityListeners[Events::postRemove][0]; + $preRemove = $metadata->entityListeners[Events::preRemove][0]; + $postLoad = $metadata->entityListeners[Events::postLoad][0]; + $preFlush = $metadata->entityListeners[Events::preFlush][0]; + + + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddressListener', $postPersist['class']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddressListener', $prePersist['class']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddressListener', $postUpdate['class']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddressListener', $preUpdate['class']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddressListener', $postRemove['class']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddressListener', $preRemove['class']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddressListener', $postLoad['class']); + $this->assertEquals('Doctrine\Tests\Models\CMS\CmsAddressListener', $preFlush['class']); + + $this->assertEquals(Events::postPersist, $postPersist['method']); + $this->assertEquals(Events::prePersist, $prePersist['method']); + $this->assertEquals(Events::postUpdate, $postUpdate['method']); + $this->assertEquals(Events::preUpdate, $preUpdate['method']); + $this->assertEquals(Events::postRemove, $postRemove['method']); + $this->assertEquals(Events::preRemove, $preRemove['method']); + $this->assertEquals(Events::postLoad, $postLoad['method']); + $this->assertEquals(Events::preFlush, $preFlush['method']); + } } /** diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php index fba8c9db8..24739a50c 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php +++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.CMS.CmsAddress.php @@ -28,8 +28,6 @@ $metadata->mapOneToOne(array( 'joinColumns' => array(array('referencedColumnName' => 'id')) )); -$metadata->addLifecycleCallback('prePersistHandler', 'prePersist'); - $metadata->addNamedNativeQuery(array ( 'name' => 'find-all', 'query' => 'SELECT id, country, city FROM cms_addresses', @@ -89,4 +87,16 @@ $metadata->addSqlResultSetMapping(array ( 'name' => 'count', ), ) -)); \ No newline at end of file +)); + +$metadata->addEntityListener(\Doctrine\ORM\Events::postPersist, 'CmsAddressListener', 'postPersist'); +$metadata->addEntityListener(\Doctrine\ORM\Events::prePersist, 'CmsAddressListener', 'prePersist'); + +$metadata->addEntityListener(\Doctrine\ORM\Events::postUpdate, 'CmsAddressListener', 'postUpdate'); +$metadata->addEntityListener(\Doctrine\ORM\Events::preUpdate, 'CmsAddressListener', 'preUpdate'); + +$metadata->addEntityListener(\Doctrine\ORM\Events::postRemove, 'CmsAddressListener', 'postRemove'); +$metadata->addEntityListener(\Doctrine\ORM\Events::preRemove, 'CmsAddressListener', 'preRemove'); + +$metadata->addEntityListener(\Doctrine\ORM\Events::preFlush, 'CmsAddressListener', 'preFlush'); +$metadata->addEntityListener(\Doctrine\ORM\Events::postLoad, 'CmsAddressListener', 'postLoad'); \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml index 0af5facda..b35569ae4 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.xml @@ -7,6 +7,10 @@ + + + + SELECT id, country, city FROM cms_addresses diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml index 696627c3c..da2afca75 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml +++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.CMS.CmsAddress.dcm.yml @@ -1,6 +1,8 @@ Doctrine\Tests\Models\CMS\CmsAddress: type: entity table: cms_address + entityListeners: + CmsAddressListener: namedNativeQueries: find-all: resultSetMapping: mapping-find-all