Merge pull request #1181 from Ocramius/feature/#385-support-fetching-entities-by-aliased-name
Support fetching entities by aliased name
This commit is contained in:
commit
00a8265fb9
@ -18,6 +18,7 @@
|
||||
"doctrine/collections": "~1.2",
|
||||
"doctrine/dbal": ">=2.5-dev,<2.6-dev",
|
||||
"doctrine/instantiator": "~1.0.1",
|
||||
"doctrine/common": ">=2.5-dev,<2.6-dev",
|
||||
"symfony/console": "~2.5"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -173,6 +173,10 @@ the life-time of their registered entities.
|
||||
- loadClassMetadata - The loadClassMetadata event occurs after the
|
||||
mapping metadata for a class has been loaded from a mapping source
|
||||
(annotations/xml/yaml). This event is not a lifecycle callback.
|
||||
- onClassMetadataNotFound - Loading class metadata for a particular
|
||||
requested class name failed. Manipulating the given event args instance
|
||||
allows providing fallback metadata even when no actual metadata exists
|
||||
or could be found. This event is not a lifecycle callback.
|
||||
- preFlush - The preFlush event occurs at the very beginning of a flush
|
||||
operation. This event is not a lifecycle callback.
|
||||
- onFlush - The onFlush event occurs after the change-sets of all
|
||||
|
89
lib/Doctrine/ORM/Event/OnClassMetadataNotFoundEventArgs.php
Normal file
89
lib/Doctrine/ORM/Event/OnClassMetadataNotFoundEventArgs.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?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\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs;
|
||||
use Doctrine\Common\Persistence\Event\ManagerEventArgs;
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Class that holds event arguments for a `onClassMetadataNotFound` event.
|
||||
*
|
||||
* This object is mutable by design, allowing callbacks having access to it to set the
|
||||
* found metadata in it, and therefore "cancelling" a `onClassMetadataNotFound` event
|
||||
*
|
||||
* @author Marco Pivetta <ocramius@gmail.com>
|
||||
* @since 2.5
|
||||
*/
|
||||
class OnClassMetadataNotFoundEventArgs extends ManagerEventArgs
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $className;
|
||||
|
||||
/**
|
||||
* @var ClassMetadata|null
|
||||
*/
|
||||
private $foundMetadata;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $className
|
||||
* @param ObjectManager $objectManager
|
||||
*/
|
||||
public function __construct($className, ObjectManager $objectManager)
|
||||
{
|
||||
$this->className = (string) $className;
|
||||
|
||||
parent::__construct($objectManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMetadata|null $classMetadata
|
||||
*/
|
||||
public function setFoundMetadata(ClassMetadata $classMetadata = null)
|
||||
{
|
||||
$this->foundMetadata = $classMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMetadata|null
|
||||
*/
|
||||
public function getFoundMetadata()
|
||||
{
|
||||
return $this->foundMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve class name for which a failed metadata fetch attempt was executed
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClassName()
|
||||
{
|
||||
return $this->className;
|
||||
}
|
||||
}
|
||||
|
@ -120,6 +120,14 @@ final class Events
|
||||
*/
|
||||
const loadClassMetadata = 'loadClassMetadata';
|
||||
|
||||
/**
|
||||
* The onClassMetadataNotFound event occurs whenever loading metadata for a class
|
||||
* failed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const onClassMetadataNotFound = 'onClassMetadataNotFound';
|
||||
|
||||
/**
|
||||
* The preFlush event occurs when the EntityManager#flush() operation is invoked,
|
||||
* but before any changes to managed entities have been calculated. This event is
|
||||
|
@ -25,6 +25,7 @@ use Doctrine\Common\Persistence\Mapping\ReflectionService;
|
||||
use Doctrine\DBAL\Platforms;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||
use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Id\BigIntegerIdentityGenerator;
|
||||
use Doctrine\ORM\Id\IdentityGenerator;
|
||||
@ -78,7 +79,7 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
@ -88,6 +89,22 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
|
||||
$this->initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function onNotFoundMetadata($className)
|
||||
{
|
||||
if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$eventArgs = new OnClassMetadataNotFoundEventArgs($className, $this->em);
|
||||
|
||||
$this->evm->dispatchEvent(Events::onClassMetadataNotFound, $eventArgs);
|
||||
|
||||
return $eventArgs->getFoundMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -20,7 +20,10 @@
|
||||
namespace Doctrine\ORM\Tools;
|
||||
|
||||
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
|
||||
use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
use Doctrine\Common\EventSubscriber;
|
||||
use Doctrine\ORM\Events;
|
||||
|
||||
/**
|
||||
* ResolveTargetEntityListener
|
||||
@ -31,13 +34,24 @@ use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.2
|
||||
*/
|
||||
class ResolveTargetEntityListener
|
||||
class ResolveTargetEntityListener implements EventSubscriber
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
* @var array[] indexed by original entity name
|
||||
*/
|
||||
private $resolveTargetEntities = array();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
Events::loadClassMetadata,
|
||||
Events::onClassMetadataNotFound
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a target-entity class name to resolve to a new class name.
|
||||
*
|
||||
@ -53,15 +67,36 @@ class ResolveTargetEntityListener
|
||||
$this->resolveTargetEntities[ltrim($originalEntity, "\\")] = $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OnClassMetadataNotFoundEventArgs $args
|
||||
*
|
||||
* @internal this is an event callback, and should not be called directly
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onClassMetadataNotFound(OnClassMetadataNotFoundEventArgs $args)
|
||||
{
|
||||
if (array_key_exists($args->getClassName(), $this->resolveTargetEntities)) {
|
||||
$args->setFoundMetadata(
|
||||
$args
|
||||
->getObjectManager()
|
||||
->getClassMetadata($this->resolveTargetEntities[$args->getClassname()]['targetEntity'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes event and resolves new target entity names.
|
||||
*
|
||||
* @param LoadClassMetadataEventArgs $args
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @internal this is an event callback, and should not be called directly
|
||||
*/
|
||||
public function loadClassMetadata(LoadClassMetadataEventArgs $args)
|
||||
{
|
||||
/* @var $cm \Doctrine\ORM\Mapping\ClassMetadata */
|
||||
$cm = $args->getClassMetadata();
|
||||
|
||||
foreach ($cm->associationMappings as $mapping) {
|
||||
@ -69,6 +104,12 @@ class ResolveTargetEntityListener
|
||||
$this->remapAssociation($cm, $mapping);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->resolveTargetEntities as $interface => $data) {
|
||||
if ($data['targetEntity'] == $cm->getName()) {
|
||||
$args->getEntityManager()->getMetadataFactory()->setMetadataFor($interface, $cm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM;
|
||||
|
||||
use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
|
||||
use PHPUnit_Framework_TestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@see \Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs}
|
||||
*
|
||||
* @covers \Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs
|
||||
*/
|
||||
class OnClassMetadataNotFoundEventArgsTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testEventArgsMutability()
|
||||
{
|
||||
/* @var $objectManager \Doctrine\Common\Persistence\ObjectManager */
|
||||
$objectManager = $this->getMock('Doctrine\Common\Persistence\ObjectManager');
|
||||
|
||||
$args = new OnClassMetadataNotFoundEventArgs('foo', $objectManager);
|
||||
|
||||
$this->assertSame('foo', $args->getClassName());
|
||||
$this->assertSame($objectManager, $args->getObjectManager());
|
||||
|
||||
$this->assertNull($args->getFoundMetadata());
|
||||
|
||||
/* @var $metadata \Doctrine\Common\Persistence\Mapping\ClassMetadata */
|
||||
$metadata = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata');
|
||||
|
||||
$args->setFoundMetadata($metadata);
|
||||
|
||||
$this->assertSame($metadata, $args->getFoundMetadata());
|
||||
|
||||
$args->setFoundMetadata(null);
|
||||
|
||||
$this->assertNull($args->getFoundMetadata());
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Mapping;
|
||||
|
||||
use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\Tests\Mocks\MetadataDriverMock;
|
||||
use Doctrine\Tests\Mocks\EntityManagerMock;
|
||||
use Doctrine\Tests\Mocks\ConnectionMock;
|
||||
@ -322,6 +324,40 @@ class ClassMetadataFactoryTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertEquals('group-id', $groups['joinTable']['inverseJoinColumns'][0]['referencedColumnName']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3385
|
||||
* @group 1181
|
||||
* @group 385
|
||||
*/
|
||||
public function testFallbackLoadingCausesEventTriggeringThatCanModifyFetchedMetadata()
|
||||
{
|
||||
$test = $this;
|
||||
/* @var $metadata \Doctrine\Common\Persistence\Mapping\ClassMetadata */
|
||||
$metadata = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadata');
|
||||
$cmf = new ClassMetadataFactory();
|
||||
$mockDriver = new MetadataDriverMock();
|
||||
$em = $this->_createEntityManager($mockDriver);
|
||||
$listener = $this->getMock('stdClass', array('onClassMetadataNotFound'));
|
||||
$eventManager = $em->getEventManager();
|
||||
|
||||
$cmf->setEntityManager($em);
|
||||
|
||||
$listener
|
||||
->expects($this->any())
|
||||
->method('onClassMetadataNotFound')
|
||||
->will($this->returnCallback(function (OnClassMetadataNotFoundEventArgs $args) use ($metadata, $em, $test) {
|
||||
$test->assertNull($args->getFoundMetadata());
|
||||
$test->assertSame('Foo', $args->getClassName());
|
||||
$test->assertSame($em, $args->getObjectManager());
|
||||
|
||||
$args->setFoundMetadata($metadata);
|
||||
}));
|
||||
|
||||
$eventManager->addEventListener(array(Events::onClassMetadataNotFound), $listener);
|
||||
|
||||
$this->assertSame($metadata, $cmf->getMetadataFor('Foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3427
|
||||
*/
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Tools;
|
||||
|
||||
use Doctrine\ORM\Events;
|
||||
use Doctrine\ORM\Mapping\ClassMetadataFactory;
|
||||
use Doctrine\ORM\Tools\ResolveTargetEntityListener;
|
||||
use Doctrine\ORM\Events;
|
||||
|
||||
class ResolveTargetEntityListenerTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
@ -29,9 +29,8 @@ class ResolveTargetEntityListenerTest extends \Doctrine\Tests\OrmTestCase
|
||||
|
||||
$this->em = $this->_getTestEntityManager();
|
||||
$this->em->getConfiguration()->setMetadataDriverImpl($annotationDriver);
|
||||
$this->factory = new ClassMetadataFactory;
|
||||
$this->factory->setEntityManager($this->em);
|
||||
$this->listener = new ResolveTargetEntityListener;
|
||||
$this->factory = $this->em->getMetadataFactory();
|
||||
$this->listener = new ResolveTargetEntityListener();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,13 +49,37 @@ class ResolveTargetEntityListenerTest extends \Doctrine\Tests\OrmTestCase
|
||||
'Doctrine\Tests\ORM\Tools\TargetEntity',
|
||||
array()
|
||||
);
|
||||
$evm->addEventListener(Events::loadClassMetadata, $this->listener);
|
||||
$evm->addEventSubscriber($this->listener);
|
||||
|
||||
$cm = $this->factory->getMetadataFor('Doctrine\Tests\ORM\Tools\ResolveTargetEntity');
|
||||
$meta = $cm->associationMappings;
|
||||
|
||||
$this->assertSame('Doctrine\Tests\ORM\Tools\TargetEntity', $meta['manyToMany']['targetEntity']);
|
||||
$this->assertSame('Doctrine\Tests\ORM\Tools\ResolveTargetEntity', $meta['manyToOne']['targetEntity']);
|
||||
$this->assertSame('Doctrine\Tests\ORM\Tools\ResolveTargetEntity', $meta['oneToMany']['targetEntity']);
|
||||
$this->assertSame('Doctrine\Tests\ORM\Tools\TargetEntity', $meta['oneToOne']['targetEntity']);
|
||||
|
||||
$this->assertSame($cm, $this->factory->getMetadataFor('Doctrine\Tests\ORM\Tools\ResolveTargetInterface'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-3385
|
||||
* @group 1181
|
||||
* @group 385
|
||||
*/
|
||||
public function testResolveTargetEntityListenerCanRetrieveTargetEntityByInterfaceName()
|
||||
{
|
||||
$this->listener->addResolveTargetEntity(
|
||||
'Doctrine\Tests\ORM\Tools\ResolveTargetInterface',
|
||||
'Doctrine\Tests\ORM\Tools\ResolveTargetEntity',
|
||||
array()
|
||||
);
|
||||
|
||||
$this->em->getEventManager()->addEventSubscriber($this->listener);
|
||||
|
||||
$cm = $this->factory->getMetadataFor('Doctrine\Tests\ORM\Tools\ResolveTargetInterface');
|
||||
|
||||
$this->assertSame($this->factory->getMetadataFor('Doctrine\Tests\ORM\Tools\ResolveTargetEntity'), $cm);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user