vendor/api-platform/core/src/Core/Metadata/Extractor/XmlExtractor.php line 102

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the API Platform project.
  4.  *
  5.  * (c) Kévin Dunglas <dunglas@gmail.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. declare(strict_types=1);
  11. namespace ApiPlatform\Core\Metadata\Extractor;
  12. use ApiPlatform\Exception\InvalidArgumentException;
  13. use ApiPlatform\Metadata\Extractor\AbstractResourceExtractor;
  14. use ApiPlatform\Metadata\Extractor\PropertyExtractorInterface;
  15. use ApiPlatform\Metadata\Extractor\XmlPropertyExtractor;
  16. use ApiPlatform\Metadata\Extractor\XmlResourceExtractor;
  17. use Symfony\Component\Config\Util\XmlUtils;
  18. /**
  19.  * Extracts an array of metadata from a list of XML files.
  20.  *
  21.  * @author Kévin Dunglas <dunglas@gmail.com>
  22.  * @author Antoine Bluchet <soyuka@gmail.com>
  23.  * @author Baptiste Meyer <baptiste.meyer@gmail.com>
  24.  * @author Vincent Chalamon <vincentchalamon@gmail.com>
  25.  *
  26.  * @deprecated since 2.7, to remove in 3.0 (replaced by ApiPlatform\Metadata\Extractor\XmlExtractor)
  27.  */
  28. final class XmlExtractor extends AbstractResourceExtractor implements PropertyExtractorInterface
  29. {
  30.     public const RESOURCE_SCHEMA __DIR__.'/../schema/metadata.xsd';
  31.     private $properties;
  32.     /**
  33.      * {@inheritdoc}
  34.      */
  35.     public function getProperties(): array
  36.     {
  37.         if (null !== $this->properties) {
  38.             return $this->properties;
  39.         }
  40.         $this->properties = [];
  41.         foreach ($this->paths as $path) {
  42.             $this->extractPath($path);
  43.         }
  44.         return $this->properties;
  45.     }
  46.     /**
  47.      * {@inheritdoc}
  48.      */
  49.     protected function extractPath(string $path)
  50.     {
  51.         try {
  52.             /** @var \SimpleXMLElement $xml */
  53.             $xml simplexml_import_dom(XmlUtils::loadFile($pathself::RESOURCE_SCHEMA));
  54.         } catch (\InvalidArgumentException $e) {
  55.             // Test if this is a new resource
  56.             try {
  57.                 $xml XmlUtils::loadFile($pathXmlResourceExtractor::SCHEMA);
  58.                 return;
  59.             } catch (\InvalidArgumentException $newResourceException) {
  60.                 try {
  61.                     $xml XmlUtils::loadFile($pathXmlPropertyExtractor::SCHEMA);
  62.                     return;
  63.                 } catch (\InvalidArgumentException $newPropertyException) {
  64.                     throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
  65.                 }
  66.             }
  67.         }
  68.         foreach ($xml->resource as $resource) {
  69.             $resourceClass $this->resolve((string) $resource['class']);
  70.             $this->resources[$resourceClass] = [
  71.                 'shortName' => $this->phpizeAttribute($resource'shortName''string'),
  72.                 'description' => $this->phpizeAttribute($resource'description''string'),
  73.                 'iri' => $this->phpizeAttribute($resource'iri''string'),
  74.                 'itemOperations' => $this->extractOperations($resource'itemOperation'),
  75.                 'collectionOperations' => $this->extractOperations($resource'collectionOperation'),
  76.                 'subresourceOperations' => $this->extractOperations($resource'subresourceOperation'),
  77.                 'graphql' => $this->extractOperations($resource'operation'),
  78.                 'attributes' => $this->extractAttributes($resource'attribute') ?: null,
  79.                 'properties' => $this->extractProperties($resource) ?: null,
  80.             ];
  81.             $this->properties[$resourceClass] = $this->resources[$resourceClass]['properties'];
  82.         }
  83.     }
  84.     /**
  85.      * Returns the array containing configured operations. Returns NULL if there is no operation configuration.
  86.      */
  87.     private function extractOperations(\SimpleXMLElement $resourcestring $operationType): ?array
  88.     {
  89.         $graphql 'operation' === $operationType;
  90.         if (!$graphql && $legacyOperations $this->extractAttributes($resource$operationType)) {
  91.             @trigger_error(
  92.                 sprintf('Configuring "%1$s" tags without using a parent "%1$ss" tag is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3'$operationType),
  93.                 \E_USER_DEPRECATED
  94.             );
  95.             return $legacyOperations;
  96.         }
  97.         $operationsParent $graphql 'graphql' "{$operationType}s";
  98.         if (!isset($resource->{$operationsParent})) {
  99.             return null;
  100.         }
  101.         return $this->extractAttributes($resource->{$operationsParent}, $operationTypetrue);
  102.     }
  103.     /**
  104.      * Recursively transforms an attribute structure into an associative array.
  105.      */
  106.     private function extractAttributes(\SimpleXMLElement $resourcestring $elementNamebool $topLevel false): array
  107.     {
  108.         $attributes = [];
  109.         foreach ($resource->{$elementName} as $attribute) {
  110.             $value = isset($attribute->attribute[0]) ? $this->extractAttributes($attribute'attribute') : $this->phpizeContent($attribute);
  111.             // allow empty operations definition, like <collectionOperation name="post" />
  112.             if ($topLevel && '' === $value) {
  113.                 $value = [];
  114.             }
  115.             if (isset($attribute['name'])) {
  116.                 $attributes[(string) $attribute['name']] = $value;
  117.             } else {
  118.                 $attributes[] = $value;
  119.             }
  120.         }
  121.         return $attributes;
  122.     }
  123.     /**
  124.      * Gets metadata of a property.
  125.      */
  126.     private function extractProperties(\SimpleXMLElement $resource): array
  127.     {
  128.         $properties = [];
  129.         foreach ($resource->property as $property) {
  130.             $properties[(string) $property['name']] = [
  131.                 'description' => $this->phpizeAttribute($property'description''string'),
  132.                 'readable' => $this->phpizeAttribute($property'readable''bool'),
  133.                 'writable' => $this->phpizeAttribute($property'writable''bool'),
  134.                 'readableLink' => $this->phpizeAttribute($property'readableLink''bool'),
  135.                 'writableLink' => $this->phpizeAttribute($property'writableLink''bool'),
  136.                 'required' => $this->phpizeAttribute($property'required''bool'),
  137.                 'identifier' => $this->phpizeAttribute($property'identifier''bool'),
  138.                 'iri' => $this->phpizeAttribute($property'iri''string'),
  139.                 'attributes' => $this->extractAttributes($property'attribute'),
  140.                 'subresource' => $property->subresource ? [
  141.                     'collection' => $this->phpizeAttribute($property->subresource'collection''bool'),
  142.                     'resourceClass' => $this->resolve($this->phpizeAttribute($property->subresource'resourceClass''string')),
  143.                     'maxDepth' => $this->phpizeAttribute($property->subresource'maxDepth''integer'),
  144.                 ] : null,
  145.             ];
  146.         }
  147.         return $properties;
  148.     }
  149.     /**
  150.      * Transforms an XML attribute's value in a PHP value.
  151.      *
  152.      * @return string|int|bool|null
  153.      */
  154.     private function phpizeAttribute(\SimpleXMLElement $arraystring $keystring $type)
  155.     {
  156.         if (!isset($array[$key])) {
  157.             return null;
  158.         }
  159.         switch ($type) {
  160.             case 'string':
  161.                 return (string) $array[$key];
  162.             case 'integer':
  163.                 return (int) $array[$key];
  164.             case 'bool':
  165.                 return (bool) XmlUtils::phpize($array[$key]);
  166.         }
  167.         return null;
  168.     }
  169.     /**
  170.      * Transforms an XML element's content in a PHP value.
  171.      */
  172.     private function phpizeContent(\SimpleXMLElement $array)
  173.     {
  174.         $type $array['type'] ?? null;
  175.         $value = (string) $array;
  176.         switch ($type) {
  177.             case 'string':
  178.                 return $value;
  179.             case 'constant':
  180.                 return \constant($value);
  181.             default:
  182.                 return XmlUtils::phpize($value);
  183.         }
  184.     }
  185. }