Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Reference extension #1320

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions lib/Gedmo/References/Mapping/Driver/Xml.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
/**
* Xml.php
*
* @author dbojdo - Daniel Bojdo <daniel.bojdo@dxi.eu>
* Created on May 18, 2015, 13:38
* Copyright (C) DXI Ltd
*/

namespace Gedmo\References\Mapping\Driver;

use Gedmo\Exception\RuntimeException;
use Gedmo\Mapping\Driver\Xml as BaseXml;

/**
* Class Xml
* @package Gedmo\References\Mapping\Driver
*/
class Xml extends BaseXml
{
private static $referenceTypes = array(
'referenceOne' => 'reference-one',
'referenceMany' => 'reference-many',
'referenceManyEmbed' => 'reference-many-embed'
);

/**
* Read extended metadata configuration for
* a single mapped class
*
* @param object $meta
* @param array $config
*
* @return void
*/
public function readExtendedMetadata($meta, array &$config)
{
/**
* @var \SimpleXmlElement $mapping
*/
$mapping = $this->_getMapping($meta->name);
$gedmoMapping = $mapping->children(self::GEDMO_NAMESPACE_URI);

foreach (self::$referenceTypes as $type => $tagName) {
$config[$type] = array();

if (isset($gedmoMapping->{$tagName})) {
foreach ($gedmoMapping->{$tagName} as $referenceConfig) {
$config[$type][] = $this->createReferenceConfig($tagName, $referenceConfig);
}
}
}
}

/**
* @param string $type
* @param \SimpleXMLElement $referenceConfig
* @return array
*/
private function createReferenceConfig($type, \SimpleXMLElement $referenceConfig)
{
$config = array();
$config['field'] = $this->_getAttribute($referenceConfig, 'field');
$config['type'] = $this->_getAttribute($referenceConfig, 'type');
$config['class'] = $this->_getAttribute($referenceConfig, 'class');
$config['identifier'] = $this->_getAttribute($referenceConfig, 'identifier');
$config['inversedBy'] = $this->_getAttribute($referenceConfig, 'inversed-by');
$config['mappedBy'] = $this->_getAttribute($referenceConfig, 'mapped-by');

return $config;
}
}
61 changes: 61 additions & 0 deletions lib/Gedmo/References/Mapping/Driver/Yaml.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/**
* Yaml.php
*
* @author dbojdo - Daniel Bojdo <daniel.bojdo@dxi.eu>
* Created on May 18, 2015, 14:20
* Copyright (C) DXI Ltd
*/

namespace Gedmo\References\Mapping\Driver;

use Gedmo\Mapping\Driver;
use Gedmo\Mapping\Driver\File;

/**
* Class Yaml
* @package Gedmo\References\Mapping\Driver
*/
class Yaml extends File implements Driver
{
private static $referenceTypes = array(
'referenceOne',
'referenceMany',
'referenceManyEmbed'
);

/**
* Read extended metadata configuration for
* a single mapped class
*
* @param object $meta
* @param array $config
*
* @return void
*/
public function readExtendedMetadata($meta, array &$config)
{
$mapping = $this->_getMapping($meta->name);
foreach (self::$referenceTypes as $referenceType) {
if (isset($mapping['gedmo'][$referenceType])) {
foreach ($mapping['gedmo'][$referenceType] as $field => $referenceConfig) {
$referenceConfig['field'] = $field;
$config[$referenceType][] = $referenceConfig;
}
}
}
}

/**
* Loads a mapping file with the given name and returns a map
* from class/entity names to their corresponding elements.
*
* @param string $file The mapping file to load.
*
* @return array
*/
protected function _loadMappingFile($file)
{
return \Symfony\Component\Yaml\Yaml::parse($file);
}
}
53 changes: 41 additions & 12 deletions lib/Gedmo/References/ReferencesListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\EventArgs;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\ObjectManager;
use Gedmo\Exception\RuntimeException;
use Gedmo\Mapping\MappedEventSubscriber;

/**
Expand All @@ -17,11 +19,14 @@
*/
class ReferencesListener extends MappedEventSubscriber
{
private $managers;
/**
* @var ManagerRegistry[]
*/
private $registries;

public function __construct(array $managers = array())
public function __construct(array $registries = array())
{
$this->managers = $managers;
$this->registries = $registries;
}

public function loadClassMetadata(EventArgs $eventArgs)
Expand All @@ -48,7 +53,7 @@ public function postLoad(EventArgs $eventArgs)
$property->setValue(
$object,
$ea->getSingleReference(
$this->getManager($mapping['type']),
$this->getManager($mapping['type'], $mapping['class']),
$mapping['class'],
$referencedObjectId
)
Expand All @@ -62,7 +67,7 @@ public function postLoad(EventArgs $eventArgs)
$property->setAccessible(true);
if (isset($mapping['mappedBy'])) {
$id = $ea->extractIdentifier($om, $object);
$manager = $this->getManager($mapping['type']);
$manager = $this->getManager($mapping['type'], $mapping['class']);
$class = $mapping['class'];
$refMeta = $manager->getClassMetadata($class);
$refConfig = $this->getConfiguration($manager, $refMeta->name);
Expand Down Expand Up @@ -110,19 +115,43 @@ public function getSubscribedEvents()
);
}

public function registerManager($type, $manager)
/**
* @param string $type
* @param ManagerRegistry $registry
*/
public function setRegistry($type, ManagerRegistry $registry)
{
$this->managers[$type] = $manager;
$this->registries[$type] = $registry;
}

/**
* @param string $type
*
* @param string $class
* @return ObjectManager
*/
public function getManager($type)
public function getManager($type, $class)
{
return $this->managers[$type];
if (!isset($this->registries[$type])) {
throw new RuntimeException(
sprintf('Could not find Registry with required type "%s".', $type)
);
}

$registry = $this->registries[$type];
foreach ($registry->getManagers() as $manager) {
try {
$manager->getClassMetadata($class);

return $manager;
} catch (\Exception $e) {
}
}

if (!$manager) {
throw new RuntimeException(
sprintf('Could not find Manager type "%s" for class "%s".', $type, $class)
);
}
}

protected function getNamespace()
Expand All @@ -147,7 +176,7 @@ private function updateReferences(EventArgs $eventArgs)
$object,
$mapping['identifier'],
$ea->getIdentifier(
$this->getManager($mapping['type']),
$this->getManager($mapping['type'], $mapping['class']),
$referencedObject
)
);
Expand All @@ -170,7 +199,7 @@ public function updateManyEmbedReferences(EventArgs $eventArgs)
$property->setAccessible(true);

$id = $ea->extractIdentifier($om, $object);
$manager = $this->getManager('document');
$manager = $this->getManager(RegistryTypes::DOCUMENT, $mapping['class']);

$class = $mapping['class'];
$refMeta = $manager->getClassMetadata($class);
Expand Down
20 changes: 20 additions & 0 deletions lib/Gedmo/References/RegistryTypes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
/**
* ManagerTypes.php
*
* @author dbojdo - Daniel Bojdo <daniel.bojdo@dxi.eu>
* Created on Jun 11, 2015, 15:54
* Copyright (C) DXI Ltd
*/

namespace Gedmo\References;

/**
* Class ManagerTypes
* @package Gedmo\References
*/
final class RegistryTypes
{
const ENTITY = 'entity';
const DOCUMENT = 'document';
}
19 changes: 19 additions & 0 deletions schemas/orm/doctrine-extensions-mapping-2-2.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ people to push their own additional attributes/elements into the same field elem
<xs:element name="loggable" type="gedmo:loggable"/>
<xs:element name="soft-deleteable" type="gedmo:soft-deleteable"/>
<xs:element name="uploadable" type="gedmo:uploadable"/>
<xs:element name="reference-one" type="gedmo:reference"/>
<xs:element name="reference-many" type="gedmo:reference"/>
<xs:element name="reference-many-embed" type="gedmo:reference"/>

<!-- field -->
<xs:element name="slug" type="gedmo:slug"/>
<xs:element name="translatable" type="gedmo:translatable"/>
Expand Down Expand Up @@ -163,4 +167,19 @@ people to push their own additional attributes/elements into the same field elem
<xs:attribute name="disallowed-types" type="xs:string" use="optional" />
</xs:complexType>

<xs:simpleType name="reference-type">
<xs:restriction base="xs:token">
<xs:enumeration value="entity"/>
<xs:enumeration value="document"/>
</xs:restriction>
</xs:simpleType>

<xs:complexType name="reference">
<xs:attribute name="field" type="xs:string" use="required" />
<xs:attribute name="type" type="gedmo:reference-type" use="required" />
<xs:attribute name="class" type="xs:string" use="required" />
<xs:attribute name="identifier" type="xs:string" use="required" />
<xs:attribute name="inversed-by" type="xs:string" use="optional" />
<xs:attribute name="mapped-by" type="xs:string" use="optional" />
</xs:complexType>
</xs:schema>
21 changes: 18 additions & 3 deletions tests/Gedmo/References/ReferencesListenerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

class ReferencesListenerTest extends BaseTestCaseOM
{
private $em;
private $dm;
private $em;

protected function setUp()
{
Expand All @@ -26,10 +26,13 @@ protected function setUp()

$reader = new AnnotationReader();

$documentRegistry = $this->getMockRegistry();

$this->dm = $this->getMockDocumentManager('test', new MongoDBAnnotationDriver($reader, __DIR__.'/Fixture/ODM/MongoDB'));
$documentRegistry->expects($this->any())->method('getManagers')->willReturn(array('default' => $this->dm));

$listener = new ReferencesListener(array(
'document' => $this->dm,
'document' => $documentRegistry,
));

$this->evm->addEventSubscriber($listener);
Expand All @@ -43,7 +46,11 @@ protected function setUp()
),
new ORMAnnotationDriver($reader, __DIR__.'/Fixture/ORM')
);
$listener->registerManager('entity', $this->em);

$entityRegistry = $this->getMockRegistry();
$entityRegistry->expects($this->any())->method('getManagers')->willReturn(array('default' => $this->em));

$listener->setRegistry('entity', $entityRegistry);
}

public function testShouldPersistReferencedIdentifiersIntoIdentifierField()
Expand Down Expand Up @@ -180,4 +187,12 @@ public function testShouldPopulateReferenceManyEmbedWithLazyCollectionInstance()
$this->assertInstanceOf(get_class($samsungTV), $last);
$this->assertEquals('Samsung TV', $last->getName());
}

/**
* @return \PHPUnit_Framework_MockObject_MockObject|\Doctrine\Common\Persistence\ManagerRegistry
*/
private function getMockRegistry()
{
return $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
}
}