Skip to content
This repository has been archived by the owner on Jan 1, 2020. It is now read-only.

Add chain mapper implementation #71

Merged
merged 6 commits into from
Feb 11, 2015
Merged
Show file tree
Hide file tree
Changes from 2 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
32 changes: 23 additions & 9 deletions src/Midgard/CreatePHP/Mapper/AbstractRdfMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,28 @@ 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;
}
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}
*/
Expand Down Expand Up @@ -145,14 +156,17 @@ protected function getField($object, RdfElementDefinitionInterface $child)
}

/**
* A dummy classname canonicalizer: returns the name unmodified.
* {@inheritDoc}
*
* @param string $className
* @return string exactly the same as $className
* The default implementation uses get_class on objects
*/
public function canonicalName($className)
public function objectToName($object)
{
return $className;
if (! is_object($object)) {
throw new \RuntimeException("$object is not an object");
}

return get_class($object);
}

/**
Expand Down
34 changes: 31 additions & 3 deletions src/Midgard/CreatePHP/Mapper/BaseDoctrineRdfMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@

use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\Mapping\MappingException;
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
Expand All @@ -20,7 +23,7 @@
*
* @package Midgard.CreatePHP
*/
abstract class BaseDoctrineRdfMapper extends AbstractRdfMapper
abstract class BaseDoctrineRdfMapper extends AbstractRdfMapper implements RdfChainableMapperInterface
{
/** @var ObjectManager */
protected $om;
Expand Down Expand Up @@ -58,9 +61,10 @@ public function store(EntityInterface $entity)
*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for BC, lets just keep this method as it was but add the new objectToName method.

we can then eventually go for a version 2.0 of this library, but for now lets keep things working.

* use getRealClass if className names a doctrine proxy class.
*/
public function canonicalName($className)
public function objectToName($object)
{
$refl = new \ReflectionClass($className);
$refl = new \ReflectionClass($object);
$className = $refl->getName();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as we have the object now, we should not use reflection but instead simply do this (no need even for an "if")

\Doctrine\Common\Util\ClassUtils::getClass($object);

(and lets add a use statement for Doctrine\Common\Util\ClassUtils)

if (in_array('Doctrine\\Common\\Persistence\\Proxy', $refl->getInterfaceNames())) {
$className = \Doctrine\Common\Util\ClassUtils::getRealClass($className);
}
Expand Down Expand Up @@ -94,4 +98,28 @@ public function setPropertyValue($object, PropertyInterface $property, $value)

return parent::setPropertyValue($object, $property, $value);
}

/**
* {@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;
}
}
175 changes: 175 additions & 0 deletions src/Midgard/CreatePHP/Mapper/ChainRdfMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<?php

namespace Midgard\CreatePHP\Mapper;


use Midgard\CreatePHP\RdfChainableMapperInterface;
use Midgard\CreatePHP\RdfMapperInterface;
use Midgard\CreatePHP\Entity\PropertyInterface;
use Midgard\CreatePHP\Entity\CollectionInterface;
use Midgard\CreatePHP\Type\TypeInterface;
use Midgard\CreatePHP\Entity\EntityInterface;

use \RuntimeException;

/**
* Looks at all registered mappers to find one that can handle objects.
*
* @package Midgard.CreatePHP
*/
class ChainRdfMapper implements RdfMapperInterface
{
/**
* All the registered mappers
*
* @var RdfMapperInterface[]
*/
private $mappers = array();

/**
* Mappers index by the spl_object_hash of objects created by CreatePHP
*
* @var RdfMapperInterface[]
*/
private $createdObjects = array();

/**
* Register a mapper with a key. The key will be prefixed to all subjects.
*
* @param RdfChainableMapperInterface $mapper
* @param string $mapperKey
*/
public function registerMapper(RdfChainableMapperInterface $mapper, $mapperKey)
{
$this->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)
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we follow symfony codestyle, this { would need to be at the end of the line above.

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 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("No mapper can create an object for type.");
}

/**
* {@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("No mapper can create a subject for object.");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets do
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);
}
}
2 changes: 1 addition & 1 deletion src/Midgard/CreatePHP/Mapper/DoctrineOrmMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}

/**
Expand Down
13 changes: 0 additions & 13 deletions src/Midgard/CreatePHP/Metadata/AbstractRdfDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,6 @@ protected abstract function getConfig($element);
*/
protected abstract function getAttributes($element);

/**
* {@inheritDoc}
*
* The default implementation uses get_class on objects
*/
public function objectToName($object, RdfMapperInterface $mapper)
{
if (! is_object($object)) {
throw new \RuntimeException("$object is not an object");
}
return $mapper->canonicalName(get_class($object));
}

/**
* Create a type instance.
*
Expand Down
9 changes: 0 additions & 9 deletions src/Midgard/CreatePHP/Metadata/RdfDriverInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,6 @@ interface RdfDriverInterface
*/
public function loadType($name, RdfMapperInterface $mapper, RdfTypeFactory $typeFactory);

/**
* Get the name of an object
*
* @param object $object
*
* @return string the canonical name of this object
*/
public function objectToName($object, RdfMapperInterface $mapper);

/**
* Gets a map of rdf types to names with all types known to this driver.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Midgard/CreatePHP/Metadata/RdfTypeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
);
}

Expand Down
39 changes: 39 additions & 0 deletions src/Midgard/CreatePHP/RdfChainableMapperInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
/**
* @copyright CONTENT CONTROL GmbH, http://www.contentcontrol-berlin.de
* @author CONTENT CONTROL GmbH, http://www.contentcontrol-berlin.de
* @license Dual licensed under the MIT (MIT-LICENSE.txt) and LGPL (LGPL-LICENSE.txt) licenses.
* @package Midgard.CreatePHP
*/

namespace Midgard\CreatePHP;

use Midgard\CreatePHP\Type\TypeInterface;

/**
* Map from CreatePHP to your domain objects
*
* You can have a mapper per type or a generic mapper that handles all types.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please update this description to explain what the chainable mapper is. the general description of what a mapper is can stay in RdfMapperInterface

*
* @package Midgard.CreatePHP
*/
interface RdfChainableMapperInterface extends RdfMapperInterface
{
/**
* Get if the object can be handled by this mapper.
*
* @param mixed $object
*
* @return boolean
*/
public function supports($object);

/**
* Get if this mapper can create this type.
*
* @param TypeInterface $type
*
* @return boolean
*/
public function supportsCreate(TypeInterface $type);
}
Loading