diff --git a/Description/Descriptor.php b/Description/Descriptor.php index 9b0e2b1..28955ee 100644 --- a/Description/Descriptor.php +++ b/Description/Descriptor.php @@ -19,21 +19,25 @@ final class Descriptor { /** * Alias for the resource type for example `app.page`. + * Value should be a scalar string. */ const TYPE_ALIAS = 'type.alias'; /** * Humanized representation of the resource type. + * Value should be a scalar string. */ const TYPE_TITLE = 'type.title'; /** * Title of the actual payload, e.g. "My Blog Post". + * Value should be a scalar string. */ const PAYLOAD_TITLE = 'title'; /** * Descriptors for HTML links. + * Values should be either a valid URI. */ const LINK_EDIT_HTML = 'link.edit.html'; const LINK_CREATE_HTML = 'link.create.html'; @@ -44,6 +48,7 @@ final class Descriptor /** * Descriptors for REST links. + * Values should be either a valid URI. */ const LINK_EDIT_REST = 'link.edit.rest'; const LINK_CREATE_REST = 'link.create.rest'; @@ -54,8 +59,16 @@ final class Descriptor /** * Permitted children types for this resource. - * Value is an array. + * Value should be a scalar array, e.g. [ `stdClass`, `FooClass` ] + * + * NOTE: This should be an explicit list of types and should not include + * interfaces are abstract class names. */ const CHILDREN_TYPES = 'children.types'; + + /** + * If children are allowed to be added to this resource. + * Value should be a boolean. + */ const CHILDREN_ALLOW = 'children.allow'; } diff --git a/Description/Enhancer/Doctrine/PhpcrOdm/PhpcrOdmEnhancer.php b/Description/Enhancer/Doctrine/PhpcrOdm/PhpcrOdmEnhancer.php index ece297b..6e2ed94 100644 --- a/Description/Enhancer/Doctrine/PhpcrOdm/PhpcrOdmEnhancer.php +++ b/Description/Enhancer/Doctrine/PhpcrOdm/PhpcrOdmEnhancer.php @@ -39,9 +39,20 @@ public function __construct(ClassMetadataFactory $metadataFactory) public function enhance(Description $description) { $metadata = $this->metadataFactory->getMetadataFor($description->getResource()->getPayloadType()); + $childClasses = $metadata->getChildClasses(); + $childTypes = []; + + // explode the allowed types into concrete classes + foreach ($this->metadataFactory->getAllMetadata() as $childMetadata) { + foreach ($childClasses as $childClass) { + if ($childClass == $childMetadata->name || $childMetadata->getReflectionClass()->isSubclassOf($childClass)) { + $childTypes[] = $childMetadata->name; + } + } + } $description->set(Descriptor::CHILDREN_ALLOW, !$metadata->isLeaf()); - $description->set(Descriptor::CHILDREN_TYPES, $metadata->getChildClasses()); + $description->set(Descriptor::CHILDREN_TYPES, $childTypes); } /** diff --git a/Tests/Unit/Description/Enhancer/Doctrine/PhpcrOdm/PhpcrOdmEnhancerTest.php b/Tests/Unit/Description/Enhancer/Doctrine/PhpcrOdm/PhpcrOdmEnhancerTest.php index a230f21..a3c5793 100644 --- a/Tests/Unit/Description/Enhancer/Doctrine/PhpcrOdm/PhpcrOdmEnhancerTest.php +++ b/Tests/Unit/Description/Enhancer/Doctrine/PhpcrOdm/PhpcrOdmEnhancerTest.php @@ -18,6 +18,7 @@ use Symfony\Cmf\Component\Resource\Description\Enhancer\Doctrine\PhpcrOdm\PhpcrOdmEnhancer; use Puli\Repository\Api\Resource\PuliResource; use Doctrine\ODM\PHPCR\Mapping\ClassMetadata; +use Symfony\Cmf\Component\Resource\Repository\Resource\PhpcrResource; class PhpcrOdmEnhancerTest extends \PHPUnit_Framework_TestCAse { @@ -77,20 +78,65 @@ public function testNotSupportsNotSupportedByPhpcrOdm() */ public function testEnhanceDescription() { + // object the implements an allowed interface + $mappedObject1 = $this->prophesize(); + $mappedObject1->willImplement(FooInterface::class); + $metadata1 = $this->prophesize(ClassMetadata::class); + $metadata1->name = get_class($mappedObject1->reveal()); + $metadata1->getReflectionClass()->willReturn(new \ReflectionClass($metadata1->name)); + + // object the extends an allowed class + $mappedObject2 = $this->prophesize(); + $mappedObject2->willExtend(AbstractFoo::class); + $metadata2 = $this->prophesize(ClassMetadata::class); + $metadata2->name = get_class($mappedObject2->reveal()); + $metadata2->getReflectionClass()->willReturn(new \ReflectionClass($metadata2->name)); + + // object of exact type that is allowed + $mappedObject3 = $this->prophesize(); + $metadata3 = $this->prophesize(ClassMetadata::class); + $metadata3->name = get_class($mappedObject3->reveal()); + $metadata3->getReflectionClass()->willReturn(new \ReflectionClass($metadata3->reveal())); + + // object that is not permitted + $metadata4 = $this->prophesize(ClassMetadata::class); + $metadata4->name = NotAllowedFoo::class; + $metadata4->getReflectionClass()->willReturn(new \ReflectionClass($metadata4->reveal())); + $this->description->getResource()->willReturn($this->cmfResource->reveal()); $this->cmfResource->getPayloadType()->willReturn('payload_type'); $this->metadataFactory->getMetadataFor('payload_type')->willReturn($this->odmMetadata->reveal()); + $this->metadataFactory->getAllMetadata()->willReturn([ + $metadata1->reveal(), + $metadata2->reveal(), + $metadata3->reveal(), + ]); + $this->odmMetadata->isLeaf()->willReturn(false); $this->odmMetadata->getChildClasses()->willReturn([ - 'class_1', - 'class_2', + FooInterface::class, + AbstractFoo::class, + $metadata3->name, ]); $this->description->set(Descriptor::CHILDREN_ALLOW, true)->shouldBeCalled(); $this->description->set(Descriptor::CHILDREN_TYPES, [ - 'class_1', - 'class_2', + $metadata1->name, + $metadata2->name, + $metadata3->name, ])->shouldBeCalled(); $this->enhancer->enhance($this->description->reveal()); } } + +interface FooInterface +{ +} + +class AbstractFoo +{ +} + +class NotAllowedFoo +{ +} diff --git a/composer.json b/composer.json index e330b34..26bb0af 100644 --- a/composer.json +++ b/composer.json @@ -18,10 +18,10 @@ }, "require-dev": { "phpspec/prophecy-phpunit": "~1.0.0", - "doctrine/phpcr-odm": "~1.2", "jackalope/jackalope-fs": "dev-master", "sonata-project/admin-bundle": "^3.1", - "sylius/resource-bundle": "0.18" + "sylius/resource-bundle": "0.18", + "doctrine/phpcr-odm": "^1.4" }, "suggest": { "doctrine/phpcr-odm": "To enable support for the PHPCR ODM documents",