diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f4c05c..48e8267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ Changelog ========= +1.1 +----- +* Added ChainRdfMapper and ChainedRdfMapperInterface to allow using more than one mapper in parallel. +* BC break: If you implemented your own mapper, note that RdfMapperInterface::objectToName was added + +1.0 +----- + * **2014-01-13**: Moved workflows from Manager to RestService. If you used the Manager before, please update your code to use the RestService. Before: diff --git a/composer.json b/composer.json index efdc28a..5ecc131 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ }, "extra": { "branch-alias": { - "dev-master": "0.9-dev" + "dev-master": "1.1-dev" } } } diff --git a/src/Midgard/CreatePHP/Mapper/AbstractRdfMapper.php b/src/Midgard/CreatePHP/Mapper/AbstractRdfMapper.php index 4e48e60..4ba3ea7 100644 --- a/src/Midgard/CreatePHP/Mapper/AbstractRdfMapper.php +++ b/src/Midgard/CreatePHP/Mapper/AbstractRdfMapper.php @@ -58,10 +58,7 @@ public function prepareObject(TypeInterface $type, $parent = null) if ($parent !== null) { throw new \Exception('Parent is not null, please extend this method to configure the parent'); } - list($prefix, $shortname) = explode(':', $type->getRdfType()); - $ns = $type->getVocabularies(); - $ns = $ns[$prefix]; - $name = $ns.$shortname; + $name = $this->getTypeMapKey($type); if (isset($this->typeMap[$name])) { $class = $this->typeMap[$name]; return new $class; @@ -69,6 +66,20 @@ public function prepareObject(TypeInterface $type, $parent = null) throw new \Exception('No information on ' . $name); } + /** + * Get's the possible key used in the typemap for the type + * + * @param TypeInterface $type + * @return string + */ + protected function getTypeMapKey(TypeInterface $type) + { + list($prefix, $shortname) = explode(':', $type->getRdfType()); + $ns = $type->getVocabularies(); + $ns = $ns[$prefix]; + return $ns.$shortname; + } + /** * {@inheritDoc} */ @@ -149,12 +160,27 @@ protected function getField($object, RdfElementDefinitionInterface $child) * * @param string $className * @return string exactly the same as $className + * @deprecated Deprecated in 1.1 use objectToName instead. */ public function canonicalName($className) { return $className; } + /** + * {@inheritDoc} + * + * The default implementation uses get_class on objects + */ + public function objectToName($object) + { + if (! is_object($object)) { + throw new \RuntimeException("$object is not an object"); + } + + return $this->canonicalName(get_class($object)); + } + /** * This sort method is used for sorting elements in the given array according the reference array * which contains some of the array keys of the first array. diff --git a/src/Midgard/CreatePHP/Mapper/BaseDoctrineRdfMapper.php b/src/Midgard/CreatePHP/Mapper/BaseDoctrineRdfMapper.php index 58b153d..8915de0 100644 --- a/src/Midgard/CreatePHP/Mapper/BaseDoctrineRdfMapper.php +++ b/src/Midgard/CreatePHP/Mapper/BaseDoctrineRdfMapper.php @@ -10,8 +10,12 @@ use Doctrine\Common\Persistence\ObjectManager; use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\Mapping\MappingException; +use Doctrine\Common\Util\ClassUtils; +use Midgard\CreatePHP\RdfChainableMapperInterface; use Midgard\CreatePHP\Entity\EntityInterface; use Midgard\CreatePHP\Entity\PropertyInterface; +use Midgard\CreatePHP\Type\TypeInterface; /** * Base mapper for doctrine, removing the proxy class names in canonicalClassName @@ -20,7 +24,7 @@ * * @package Midgard.CreatePHP */ -abstract class BaseDoctrineRdfMapper extends AbstractRdfMapper +abstract class BaseDoctrineRdfMapper extends AbstractRdfMapper implements RdfChainableMapperInterface { /** @var ObjectManager */ protected $om; @@ -68,6 +72,16 @@ public function canonicalName($className) return $className; } + /** + * {@inheritDoc} + * + * use getRealClass if className names a doctrine proxy class. + */ + public function objectToName($object) + { + return $this->canonicalName(ClassUtils::getClass($object)); + } + /** * {@inheritDoc} */ @@ -94,4 +108,30 @@ public function setPropertyValue($object, PropertyInterface $property, $value) return parent::setPropertyValue($object, $property, $value); } -} \ No newline at end of file + + /** + * {@inheritDoc} + */ + public function supports($object) + { + return $this->om->contains($object); + } + + /** + * {@inheritDoc} + */ + public function supportsCreate(TypeInterface $type) + { + $name = $this->getTypeMapKey($type); + if (isset($this->typeMap[$name])) { + try { + $metadata = $this->om->getClassMetadata($this->typeMap[$name]); + + return is_object($metadata); + } catch (MappingException $e) { + } + } + + return false; + } +} diff --git a/src/Midgard/CreatePHP/Mapper/ChainRdfMapper.php b/src/Midgard/CreatePHP/Mapper/ChainRdfMapper.php new file mode 100644 index 0000000..64aeb45 --- /dev/null +++ b/src/Midgard/CreatePHP/Mapper/ChainRdfMapper.php @@ -0,0 +1,177 @@ +mappers[$mapperKey] = $mapper; + } + + /** + * Get the mapper than can handle object. + * + * @param mixed $object + * @return RdfChainableMapperInterface + * @throws RuntimeException when no mapper can handle the object + */ + protected function getMapperForObject($object) + { + foreach ($this->mappers as $mapper) { + if ($mapper->supports($object)) { + return $mapper; + } + } + + $hash = spl_object_hash($object); + if (isset($this->createdObjects[$hash])) { + return $this->createdObjects[$hash]; + } + + throw new RuntimeException("No mapper can create a subject for object."); + } + /** + * {@inheritdoc} + */ + public function setPropertyValue($object, PropertyInterface $property, $value) + { + return $this->getMapperForObject($object)->setPropertyValue($object, $property, $value); + } + + /** + * {@inheritdoc} + */ + public function getPropertyValue($object, PropertyInterface $property) + { + return $this->getMapperForObject($object)->getPropertyValue($object, $property); + } + + /** + * {@inheritdoc} + */ + public function isEditable($object) + { + return $this->getMapperForObject($object)->isEditable($object); + } + + /** + * {@inheritdoc} + */ + public function getChildren($object, CollectionInterface $collection) + { + return $this->getMapperForObject($object)->getChildren($object, $collection); + } + + /** + * {@inheritdoc} + */ + public function canonicalName($className) + { + return $className; + } + + /** + * {@inheritdoc} + */ + public function objectToName($object) + { + return $this->getMapperForObject($object)->objectToName($object); + } + + /** + * {@inheritdoc} + */ + public function prepareObject(TypeInterface $controller, $parent = null) + { + foreach ($this->mappers as $mapper) { + if ($mapper->supportsCreate($controller)) { + $object = $mapper->prepareObject($controller, $parent); + $this->createdObjects[spl_object_hash($object)] = $mapper; + + return $object; + } + } + + throw new RuntimeException(sprintf('None of the registered mappers can create an object of type %s', $controller->getRdfType())); + } + + /** + * {@inheritdoc} + */ + public function store(EntityInterface $entity) + { + return $this->getMapperForObject($entity->getObject())->store($entity); + } + + /** + * {@inheritdoc} + */ + public function getBySubject($subject) + { + list($mapperKey, $mapperSubject) = explode('|', $subject, 2); + + if (!isset($this->mappers[$mapperKey])) { + throw new RuntimeException("Invalid subject: $subject"); + } + + $object = $this->mappers[$mapperKey]->getBySubject($mapperSubject); + + return $object; + } + + /** + * {@inheritdoc} + */ + public function createSubject($object) + { + foreach ($this->mappers as $mapperKey => $mapper) { + if ($mapper->supports($object)) { + return $mapperKey.'|'.$mapper->createSubject($object); + } + } + + throw new RuntimeException(sprintf('None of the registered mappers can create the subject for object of class %s', get_class($object))); + } + + /** + * {@inheritdoc} + */ + public function orderChildren(EntityInterface $entity, CollectionInterface $node, $expectedOrder) + { + return $this->getMapperForObject($entity->getObject())->orderChildren($entity, $node, $expectedOrder); + } +} diff --git a/src/Midgard/CreatePHP/Mapper/DoctrineOrmMapper.php b/src/Midgard/CreatePHP/Mapper/DoctrineOrmMapper.php index 90e7c34..2d8f3cb 100644 --- a/src/Midgard/CreatePHP/Mapper/DoctrineOrmMapper.php +++ b/src/Midgard/CreatePHP/Mapper/DoctrineOrmMapper.php @@ -55,7 +55,7 @@ public function createSubject($object) $idstring = implode('|', $key); - return str_replace('\\', '-', $this->canonicalName(get_class($object))) . "|$idstring"; + return str_replace('\\', '-', $this->objectToName($object))."|$idstring"; } /** diff --git a/src/Midgard/CreatePHP/Metadata/AbstractRdfDriver.php b/src/Midgard/CreatePHP/Metadata/AbstractRdfDriver.php index f855c68..819a473 100644 --- a/src/Midgard/CreatePHP/Metadata/AbstractRdfDriver.php +++ b/src/Midgard/CreatePHP/Metadata/AbstractRdfDriver.php @@ -74,14 +74,11 @@ protected abstract function getAttributes($element); /** * {@inheritDoc} * - * The default implementation uses get_class on objects + * @deprecated Deprecated in 1.1 call on the mapper object instead. */ public function objectToName($object, RdfMapperInterface $mapper) { - if (! is_object($object)) { - throw new \RuntimeException("$object is not an object"); - } - return $mapper->canonicalName(get_class($object)); + return $mapper->objectToName($object); } /** diff --git a/src/Midgard/CreatePHP/Metadata/RdfDriverInterface.php b/src/Midgard/CreatePHP/Metadata/RdfDriverInterface.php index e564895..52e148e 100644 --- a/src/Midgard/CreatePHP/Metadata/RdfDriverInterface.php +++ b/src/Midgard/CreatePHP/Metadata/RdfDriverInterface.php @@ -39,6 +39,8 @@ public function loadType($name, RdfMapperInterface $mapper, RdfTypeFactory $type * @param object $object * * @return string the canonical name of this object + * + * @deprecated Deprecated in 1.1 call on the mapper object instead. */ public function objectToName($object, RdfMapperInterface $mapper); diff --git a/src/Midgard/CreatePHP/Metadata/RdfTypeFactory.php b/src/Midgard/CreatePHP/Metadata/RdfTypeFactory.php index 3af3315..193cfb7 100644 --- a/src/Midgard/CreatePHP/Metadata/RdfTypeFactory.php +++ b/src/Midgard/CreatePHP/Metadata/RdfTypeFactory.php @@ -44,7 +44,7 @@ public function __construct(RdfMapperInterface $mapper, RdfDriverInterface $driv public function getTypeByObject($object) { return $this->getTypeByName( - $this->driver->objectToName($object, $this->mapper) + $this->mapper->objectToName($object) ); } diff --git a/src/Midgard/CreatePHP/RdfChainableMapperInterface.php b/src/Midgard/CreatePHP/RdfChainableMapperInterface.php new file mode 100644 index 0000000..d0c28a9 --- /dev/null +++ b/src/Midgard/CreatePHP/RdfChainableMapperInterface.php @@ -0,0 +1,38 @@ +will($this->returnValue($collection->getChildren())) ; $this->mapper->expects($this->any()) - ->method('canonicalName') - ->will($this->returnCallback(array($this, 'canonicalNameCallback'))) + ->method('objectToName') + ->will($this->returnCallback(array($this, 'objectToNameCallback'))) ; $xml = $this->renderXml('collection.twig'); @@ -147,9 +147,8 @@ public function testCollectionsTemplate() $this->assertEquals('sioc:content', $xml->ul->li[1]->div[1]['property']); } - public function canonicalNameCallback($className) { - - if ($className === 'Test\Midgard\CreatePHP\Collection') { + public function objectToNameCallback($object) { + if (get_class($object) === 'Test\Midgard\CreatePHP\Collection') { return 'Test\Midgard\CreatePHP\Collection'; } else { return 'Test\Midgard\CreatePHP\Model'; @@ -196,8 +195,8 @@ private function prepareBasicTest(){ ->will($this->returnValue('/the/subject')) ; $this->mapper->expects($this->any()) - ->method('canonicalName') - ->with(get_class($model)) + ->method('objectToName') + ->with($model) ->will($this->returnValue(get_class($model))) ; } diff --git a/tests/__files/MockMapper.php b/tests/__files/MockMapper.php index 4385fd5..b4ba10e 100644 --- a/tests/__files/MockMapper.php +++ b/tests/__files/MockMapper.php @@ -60,6 +60,11 @@ public function canonicalName($className) return $className; } + public function objectToName($object) + { + return get_class($object); + } + public function getBySubject($identifier) {