diff --git a/src/Metadata/Property/Factory/AbstractFilePropertyMetadataFactory.php b/src/Metadata/Property/Factory/AbstractFilePropertyMetadataFactory.php new file mode 100644 index 00000000000..f1d41f9347b --- /dev/null +++ b/src/Metadata/Property/Factory/AbstractFilePropertyMetadataFactory.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace ApiPlatform\Core\Metadata\Property\Factory; + +use ApiPlatform\Core\Exception\InvalidArgumentException; +use ApiPlatform\Core\Exception\PropertyNotFoundException; +use ApiPlatform\Core\Metadata\Property\PropertyMetadata; + +/** + * Common base class to load properties's metadata from files. + * + * @author Kévin Dunglas + * + * @internal + */ +abstract class AbstractFilePropertyMetadataFactory implements PropertyMetadataFactoryInterface +{ + protected $paths; + protected $decorated; + + /** + * @param string[] $paths + * @param PropertyMetadataFactoryInterface|null $decorated + */ + public function __construct(array $paths, PropertyMetadataFactoryInterface $decorated = null) + { + $this->paths = $paths; + $this->decorated = $decorated; + } + + /** + * {@inheritdoc} + */ + public function create(string $resourceClass, string $property, array $options = []): PropertyMetadata + { + $parentPropertyMetadata = null; + if ($this->decorated) { + try { + $parentPropertyMetadata = $this->decorated->create($resourceClass, $property, $options); + } catch (PropertyNotFoundException $propertyNotFoundException) { + // Ignore not found exception from decorated factories + } + } + + if ( + !property_exists($resourceClass, $property) || + empty($propertyMetadata = $this->getMetadata($resourceClass, $property)) + ) { + return $this->handleNotFound($parentPropertyMetadata, $resourceClass, $property); + } + + if ($parentPropertyMetadata) { + return $this->update($parentPropertyMetadata, $propertyMetadata); + } + + return new PropertyMetadata( + null, + $propertyMetadata['description'], + $propertyMetadata['readable'], + $propertyMetadata['writable'], + $propertyMetadata['readableLink'], + $propertyMetadata['writableLink'], + $propertyMetadata['required'], + $propertyMetadata['identifier'], + $propertyMetadata['iri'], + null, + $propertyMetadata['attributes'] + ); + } + + /** + * Extracts metadata from the XML tree. + * + * @param string $resourceClass + * @param string $propertyName + * + * @throws InvalidArgumentException + * + * @return array + */ + abstract protected function getMetadata(string $resourceClass, string $propertyName): array; + + /** + * Returns the metadata from the decorated factory if available or throws an exception. + * + * @param PropertyMetadata|null $parentPropertyMetadata + * @param string $resourceClass + * @param string $property + * + * @throws PropertyNotFoundException + * + * @return PropertyMetadata + */ + private function handleNotFound(PropertyMetadata $parentPropertyMetadata = null, string $resourceClass, string $property): PropertyMetadata + { + if ($parentPropertyMetadata) { + return $parentPropertyMetadata; + } + + throw new PropertyNotFoundException(sprintf('Property "%s" of the resource class "%s" not found.', $property, $resourceClass)); + } + + /** + * Creates a new instance of metadata if the property is not already set. + * + * @param PropertyMetadata $propertyMetadata + * @param array $metadata + * + * @return PropertyMetadata + */ + private function update(PropertyMetadata $propertyMetadata, array $metadata): PropertyMetadata + { + $metadataAccessors = [ + 'description' => 'get', + 'readable' => 'is', + 'writable' => 'is', + 'writableLink' => 'is', + 'readableLink' => 'is', + 'required' => 'is', + 'identifier' => 'is', + 'iri' => 'get', + 'attributes' => 'get', + ]; + + foreach ($metadataAccessors as $metadataKey => $accessorPrefix) { + if (null === $metadata[$metadataKey] || null !== $propertyMetadata->{$accessorPrefix.ucfirst($metadataKey)}()) { + continue; + } + + $propertyMetadata = $propertyMetadata->{'with'.ucfirst($metadataKey)}($metadata[$metadataKey]); + } + + return $propertyMetadata; + } +} diff --git a/src/Metadata/Property/Factory/XmlPropertyMetadataFactory.php b/src/Metadata/Property/Factory/XmlPropertyMetadataFactory.php index 203c517fd73..d67f26a2181 100644 --- a/src/Metadata/Property/Factory/XmlPropertyMetadataFactory.php +++ b/src/Metadata/Property/Factory/XmlPropertyMetadataFactory.php @@ -12,8 +12,6 @@ namespace ApiPlatform\Core\Metadata\Property\Factory; use ApiPlatform\Core\Exception\InvalidArgumentException; -use ApiPlatform\Core\Exception\PropertyNotFoundException; -use ApiPlatform\Core\Metadata\Property\PropertyMetadata; use Symfony\Component\Config\Util\XmlUtils; /** @@ -21,94 +19,14 @@ * * @author Baptiste Meyer */ -class XmlPropertyMetadataFactory implements PropertyMetadataFactoryInterface +final class XmlPropertyMetadataFactory extends AbstractFilePropertyMetadataFactory { const RESOURCE_SCHEMA = __DIR__.'/../../schema/metadata.xsd'; - private $paths; - private $decorated; - - /** - * @param string[] $paths - * @param PropertyMetadataFactoryInterface|null $decorated - */ - public function __construct(array $paths, PropertyMetadataFactoryInterface $decorated = null) - { - $this->paths = $paths; - $this->decorated = $decorated; - } - /** * {@inheritdoc} */ - public function create(string $resourceClass, string $property, array $options = []): PropertyMetadata - { - $parentPropertyMetadata = null; - if ($this->decorated) { - try { - $parentPropertyMetadata = $this->decorated->create($resourceClass, $property, $options); - } catch (PropertyNotFoundException $propertyNotFoundException) { - // Ignore not found exception from decorated factories - } - } - - if ( - !property_exists($resourceClass, $property) || - empty($propertyMetadata = $this->getMetadata($resourceClass, $property)) - ) { - return $this->handleNotFound($parentPropertyMetadata, $resourceClass, $property); - } - - if ($parentPropertyMetadata) { - return $this->update($parentPropertyMetadata, $propertyMetadata); - } - - return new PropertyMetadata( - null, - $propertyMetadata['description'], - $propertyMetadata['readable'], - $propertyMetadata['writable'], - $propertyMetadata['readableLink'], - $propertyMetadata['writableLink'], - $propertyMetadata['required'], - $propertyMetadata['identifier'], - $propertyMetadata['iri'], - null, - $propertyMetadata['attributes'] - ); - } - - /** - * Returns the metadata from the decorated factory if available or throws an exception. - * - * @param PropertyMetadata|null $parentPropertyMetadata - * @param string $resourceClass - * @param string $property - * - * @throws PropertyNotFoundException - * - * @return PropertyMetadata - */ - private function handleNotFound(PropertyMetadata $parentPropertyMetadata = null, string $resourceClass, string $property): PropertyMetadata - { - if ($parentPropertyMetadata) { - return $parentPropertyMetadata; - } - - throw new PropertyNotFoundException(sprintf('Property "%s" of the resource class "%s" not found.', $property, $resourceClass)); - } - - /** - * Extracts metadata from the XML tree. - * - * @param string $resourceClass - * @param string $propertyName - * - * @throws InvalidArgumentException - * - * @return array - */ - private function getMetadata(string $resourceClass, string $propertyName): array + protected function getMetadata(string $resourceClass, string $propertyName): array { foreach ($this->paths as $path) { try { @@ -166,37 +84,4 @@ private function getAttributes(\SimpleXMLElement $element): array return $attributes; } - - /** - * Creates a new instance of metadata if the property is not already set. - * - * @param PropertyMetadata $propertyMetadata - * @param array $metadata - * - * @return PropertyMetadata - */ - private function update(PropertyMetadata $propertyMetadata, array $metadata): PropertyMetadata - { - $metadataAccessors = [ - 'description' => 'get', - 'readable' => 'is', - 'writable' => 'is', - 'writableLink' => 'is', - 'readableLink' => 'is', - 'required' => 'is', - 'identifier' => 'is', - 'iri' => 'get', - 'attributes' => 'get', - ]; - - foreach ($metadataAccessors as $metadataKey => $accessorPrefix) { - if (null === $metadata[$metadataKey] || null !== $propertyMetadata->{$accessorPrefix.ucfirst($metadataKey)}()) { - continue; - } - - $propertyMetadata = $propertyMetadata->{'with'.ucfirst($metadataKey)}($metadata[$metadataKey]); - } - - return $propertyMetadata; - } } diff --git a/src/Metadata/Property/Factory/XmlPropertyNameCollectionFactory.php b/src/Metadata/Property/Factory/XmlPropertyNameCollectionFactory.php index b980180d501..3dd31510c8c 100644 --- a/src/Metadata/Property/Factory/XmlPropertyNameCollectionFactory.php +++ b/src/Metadata/Property/Factory/XmlPropertyNameCollectionFactory.php @@ -21,7 +21,7 @@ * * @author Baptiste Meyer */ -class XmlPropertyNameCollectionFactory implements PropertyNameCollectionFactoryInterface +final class XmlPropertyNameCollectionFactory implements PropertyNameCollectionFactoryInterface { const RESOURCE_SCHEMA = __DIR__.'/../../schema/metadata.xsd'; diff --git a/src/Metadata/Property/Factory/YamlPropertyMetadataFactory.php b/src/Metadata/Property/Factory/YamlPropertyMetadataFactory.php index 15e5aee599c..2d52e800c28 100644 --- a/src/Metadata/Property/Factory/YamlPropertyMetadataFactory.php +++ b/src/Metadata/Property/Factory/YamlPropertyMetadataFactory.php @@ -12,8 +12,6 @@ namespace ApiPlatform\Core\Metadata\Property\Factory; use ApiPlatform\Core\Exception\InvalidArgumentException; -use ApiPlatform\Core\Exception\PropertyNotFoundException; -use ApiPlatform\Core\Metadata\Property\PropertyMetadata; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Yaml; @@ -22,93 +20,14 @@ * * @author Baptiste Meyer */ -class YamlPropertyMetadataFactory implements PropertyMetadataFactoryInterface +final class YamlPropertyMetadataFactory extends AbstractFilePropertyMetadataFactory { - private $paths; - private $decorated; - - /** - * @param array $paths - * @param PropertyMetadataFactoryInterface|null $decorated - */ - public function __construct(array $paths, PropertyMetadataFactoryInterface $decorated = null) - { - $this->paths = $paths; - $this->decorated = $decorated; - } - /** * {@inheritdoc} - */ - public function create(string $resourceClass, string $property, array $options = []): PropertyMetadata - { - $parentPropertyMetadata = null; - if ($this->decorated) { - try { - $parentPropertyMetadata = $this->decorated->create($resourceClass, $property, $options); - } catch (PropertyNotFoundException $propertyNotFoundException) { - // Ignore not found exception from decorated factories - } - } - - if ( - !property_exists($resourceClass, $property) || - empty($propertyMetadata = $this->getMetadata($resourceClass, $property)) - ) { - return $this->handleNotFound($parentPropertyMetadata, $resourceClass, $property); - } - - if ($parentPropertyMetadata) { - return $this->update($parentPropertyMetadata, $propertyMetadata); - } - - return new PropertyMetadata( - null, - $propertyMetadata['description'], - $propertyMetadata['readable'], - $propertyMetadata['writable'], - $propertyMetadata['readableLink'], - $propertyMetadata['writableLink'], - $propertyMetadata['required'], - $propertyMetadata['identifier'], - $propertyMetadata['iri'], - null, - $propertyMetadata['attributes'] - ); - } - - /** - * Returns the metadata from the decorated factory if available or throws an exception. - * - * @param PropertyMetadata|null $parentPropertyMetadata - * @param string $resourceClass - * @param string $property - * - * @throws PropertyNotFoundException - * - * @return PropertyMetadata - */ - private function handleNotFound(PropertyMetadata $parentPropertyMetadata = null, string $resourceClass, string $property): PropertyMetadata - { - if ($parentPropertyMetadata) { - return $parentPropertyMetadata; - } - - throw new PropertyNotFoundException(sprintf('Property "%s" of the resource class "%s" not found.', $property, $resourceClass)); - } - - /** - * Extracts metadata from the YAML tree. - * - * @param string $resourceClass - * @param string $property * * @throws ParseException - * @throws InvalidArgumentException - * - * @return array */ - private function getMetadata(string $resourceClass, string $property): array + protected function getMetadata(string $resourceClass, string $property): array { foreach ($this->paths as $path) { try { @@ -178,37 +97,4 @@ private function getMetadata(string $resourceClass, string $property): array return []; } - - /** - * Creates a new instance of metadata if the property is not already set. - * - * @param PropertyMetadata $propertyMetadata - * @param array $metadata - * - * @return PropertyMetadata - */ - private function update(PropertyMetadata $propertyMetadata, array $metadata): PropertyMetadata - { - $metadataAccessors = [ - 'description' => 'get', - 'readable' => 'is', - 'writable' => 'is', - 'writableLink' => 'is', - 'readableLink' => 'is', - 'required' => 'is', - 'identifier' => 'is', - 'iri' => 'get', - 'attributes' => 'get', - ]; - - foreach ($metadataAccessors as $metadataKey => $accessorPrefix) { - if (null === $metadata[$metadataKey] || null !== $propertyMetadata->{$accessorPrefix.ucfirst($metadataKey)}()) { - continue; - } - - $propertyMetadata = $propertyMetadata->{'with'.ucfirst($metadataKey)}($metadata[$metadataKey]); - } - - return $propertyMetadata; - } } diff --git a/src/Metadata/Property/Factory/YamlPropertyNameCollectionFactory.php b/src/Metadata/Property/Factory/YamlPropertyNameCollectionFactory.php index 3d48f3b06df..a5997aa711c 100644 --- a/src/Metadata/Property/Factory/YamlPropertyNameCollectionFactory.php +++ b/src/Metadata/Property/Factory/YamlPropertyNameCollectionFactory.php @@ -22,7 +22,7 @@ * * @author Baptiste Meyer */ -class YamlPropertyNameCollectionFactory implements PropertyNameCollectionFactoryInterface +final class YamlPropertyNameCollectionFactory implements PropertyNameCollectionFactoryInterface { private $paths; private $decorated;