Skip to content

Commit 834bda5

Browse files
committed
Merge XML and YAML factories
1 parent 38fa18e commit 834bda5

26 files changed

+800
-1209
lines changed

src/Bridge/Symfony/Bundle/Resources/config/metadata.xml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
<!-- Extractor -->
1010

11-
<service id="api_platform.metadata.extractor.yaml" class="ApiPlatform\Core\Metadata\YamlExtractor" public="false" />
12-
<service id="api_platform.metadata.extractor.xml" class="ApiPlatform\Core\Metadata\XmlExtractor" public="false" />
11+
<service id="api_platform.metadata.extractor.yaml" class="ApiPlatform\Core\Metadata\Extractor\YamlExtractor" public="false" />
12+
<service id="api_platform.metadata.extractor.xml" class="ApiPlatform\Core\Metadata\Extractor\XmlExtractor" public="false" />
1313

1414
<!-- Resource name collection -->
1515

@@ -24,12 +24,12 @@
2424
<argument type="service" id="api_platform.metadata.resource.name_collection_factory.cached.inner" />
2525
</service>
2626

27-
<service id="api_platform.metadata.resource.name_collection_factory.yaml" decorates="api_platform.metadata.resource.name_collection_factory" class="ApiPlatform\Core\Metadata\Resource\Factory\YamlResourceNameCollectionFactory" public="false">
27+
<service id="api_platform.metadata.resource.name_collection_factory.yaml" decorates="api_platform.metadata.resource.name_collection_factory" class="ApiPlatform\Core\Metadata\Resource\Factory\ExtractorResourceNameCollectionFactory" public="false">
2828
<argument type="service" id="api_platform.metadata.extractor.yaml" />
2929
<argument type="service" id="api_platform.metadata.resource.name_collection_factory.yaml.inner" />
3030
</service>
3131

32-
<service id="api_platform.metadata.resource.name_collection_factory.xml" decorates="api_platform.metadata.resource.name_collection_factory" class="ApiPlatform\Core\Metadata\Resource\Factory\XmlResourceNameCollectionFactory" public="false">
32+
<service id="api_platform.metadata.resource.name_collection_factory.xml" decorates="api_platform.metadata.resource.name_collection_factory" class="ApiPlatform\Core\Metadata\Resource\Factory\ExtractorResourceNameCollectionFactory" public="false">
3333
<argument type="service" id="api_platform.metadata.extractor.xml" />
3434
<argument type="service" id="api_platform.metadata.resource.name_collection_factory.xml.inner" />
3535
</service>
@@ -46,12 +46,12 @@
4646
<argument type="service" id="api_platform.metadata.resource.metadata_factory.php_doc.inner" />
4747
</service>
4848

49-
<service id="api_platform.metadata.resource.metadata_factory.yaml" decorates="api_platform.metadata.resource.metadata_factory" class="ApiPlatform\Core\Metadata\Resource\Factory\YamlResourceMetadataFactory" decoration-priority="40" public="false">
49+
<service id="api_platform.metadata.resource.metadata_factory.yaml" decorates="api_platform.metadata.resource.metadata_factory" class="ApiPlatform\Core\Metadata\Resource\Factory\ExtractorResourceMetadataFactory" decoration-priority="40" public="false">
5050
<argument type="service" id="api_platform.metadata.extractor.yaml" />
5151
<argument type="service" id="api_platform.metadata.resource.metadata_factory.yaml.inner" />
5252
</service>
5353

54-
<service id="api_platform.metadata.resource.metadata_factory.xml" decorates="api_platform.metadata.resource.metadata_factory" class="ApiPlatform\Core\Metadata\Resource\Factory\XmlResourceMetadataFactory" decoration-priority="40" public="false">
54+
<service id="api_platform.metadata.resource.metadata_factory.xml" decorates="api_platform.metadata.resource.metadata_factory" class="ApiPlatform\Core\Metadata\Resource\Factory\ExtractorResourceMetadataFactory" decoration-priority="40" public="false">
5555
<argument type="service" id="api_platform.metadata.extractor.xml" />
5656
<argument type="service" id="api_platform.metadata.resource.metadata_factory.xml.inner" />
5757
</service>
@@ -95,12 +95,12 @@
9595
<argument type="service" id="api_platform.metadata.property.name_collection_factory.cached.inner" />
9696
</service>
9797

98-
<service id="api_platform.metadata.property.name_collection_factory.yaml" class="ApiPlatform\Core\Metadata\Property\Factory\YamlPropertyNameCollectionFactory" decorates="api_platform.metadata.property.name_collection_factory" public="false">
98+
<service id="api_platform.metadata.property.name_collection_factory.yaml" class="ApiPlatform\Core\Metadata\Property\Factory\ExtractorPropertyNameCollectionFactory" decorates="api_platform.metadata.property.name_collection_factory" public="false">
9999
<argument type="service" id="api_platform.metadata.extractor.yaml" />
100100
<argument type="service" id="api_platform.metadata.property.name_collection_factory.yaml.inner" />
101101
</service>
102102

103-
<service id="api_platform.metadata.property.name_collection_factory.xml" class="ApiPlatform\Core\Metadata\Property\Factory\XmlPropertyNameCollectionFactory" decorates="api_platform.metadata.property.name_collection_factory" public="false">
103+
<service id="api_platform.metadata.property.name_collection_factory.xml" class="ApiPlatform\Core\Metadata\Property\Factory\ExtractorPropertyNameCollectionFactory" decorates="api_platform.metadata.property.name_collection_factory" public="false">
104104
<argument type="service" id="api_platform.metadata.extractor.xml" />
105105
<argument type="service" id="api_platform.metadata.property.name_collection_factory.xml.inner" />
106106
</service>
@@ -124,12 +124,12 @@
124124
<argument type="service" id="api_platform.metadata.property.metadata_factory.inherited.inner" />
125125
</service>
126126

127-
<service id="api_platform.metadata.property.metadata_factory.yaml" class="ApiPlatform\Core\Metadata\Property\Factory\YamlPropertyMetadataFactory" decorates="api_platform.metadata.property.metadata_factory" decoration-priority="40" public="false">
127+
<service id="api_platform.metadata.property.metadata_factory.yaml" class="ApiPlatform\Core\Metadata\Property\Factory\ExtractorPropertyMetadataFactory" decorates="api_platform.metadata.property.metadata_factory" decoration-priority="40" public="false">
128128
<argument type="service" id="api_platform.metadata.extractor.yaml" />
129129
<argument type="service" id="api_platform.metadata.property.metadata_factory.yaml.inner" />
130130
</service>
131131

132-
<service id="api_platform.metadata.property.metadata_factory.xml" class="ApiPlatform\Core\Metadata\Property\Factory\XmlPropertyMetadataFactory" decorates="api_platform.metadata.property.metadata_factory" decoration-priority="40" public="false">
132+
<service id="api_platform.metadata.property.metadata_factory.xml" class="ApiPlatform\Core\Metadata\Property\Factory\ExtractorPropertyMetadataFactory" decorates="api_platform.metadata.property.metadata_factory" decoration-priority="40" public="false">
133133
<argument type="service" id="api_platform.metadata.extractor.xml" />
134134
<argument type="service" id="api_platform.metadata.property.metadata_factory.xml.inner" />
135135
</service>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace ApiPlatform\Core\Metadata\Extractor;
13+
14+
/**
15+
* Base file extractor.
16+
*
17+
* @author Kévin Dunglas <dunglas@gmail.com>
18+
*/
19+
abstract class AbstractExtractor implements ExtractorInterface
20+
{
21+
protected $paths;
22+
protected $resources;
23+
24+
/**
25+
* @param string[] $paths
26+
*/
27+
public function __construct(array $paths)
28+
{
29+
$this->paths = $paths;
30+
}
31+
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
public function getResources(): array
36+
{
37+
if (null !== $this->resources) {
38+
return $this->resources;
39+
}
40+
41+
$this->resources = [];
42+
foreach ($this->paths as $path) {
43+
$this->extractPath($path);
44+
}
45+
46+
return $this->resources;
47+
}
48+
49+
/**
50+
* Extracts metadata from a given path.
51+
*
52+
* @param string $path
53+
*/
54+
abstract protected function extractPath(string $path);
55+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace ApiPlatform\Core\Metadata\Extractor;
13+
14+
use ApiPlatform\Core\Exception\InvalidArgumentException;
15+
16+
/**
17+
* Extracts an array of metadata from a file or a list of files.
18+
*
19+
* @author Kévin Dunglas <dunglas@gmail.com>
20+
*/
21+
interface ExtractorInterface
22+
{
23+
/**
24+
* Parses all metadata files and convert them in an array.
25+
*
26+
* @throws InvalidArgumentException
27+
*
28+
* @return array
29+
*/
30+
public function getResources(): array;
31+
}

src/Metadata/XmlExtractor.php renamed to src/Metadata/Extractor/XmlExtractor.php

Lines changed: 22 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -9,72 +9,46 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace ApiPlatform\Core\Metadata;
12+
namespace ApiPlatform\Core\Metadata\Extractor;
1313

1414
use ApiPlatform\Core\Exception\InvalidArgumentException;
1515
use Symfony\Component\Config\Util\XmlUtils;
1616

1717
/**
18-
* Converts a list of XML metadata files in a PHP array.
18+
* Extracts an array of metadata from a list of XML files.
1919
*
20+
* @author Kévin Dunglas <dunglas@gmail.com>
2021
* @author Antoine Bluchet <soyuka@gmail.com>
2122
* @author Baptiste Meyer <baptiste.meyer@gmail.com>
22-
* @author Kévin Dunglas <dunglas@gmail.com>
23-
*
24-
* @internal
2523
*/
26-
final class XmlExtractor
24+
final class XmlExtractor extends AbstractExtractor
2725
{
28-
const RESOURCE_SCHEMA = __DIR__.'/schema/metadata.xsd';
29-
30-
private $paths;
31-
private $resources;
26+
const RESOURCE_SCHEMA = __DIR__.'/../schema/metadata.xsd';
3227

3328
/**
34-
* @param string[] $paths
29+
* {@inheritdoc}
3530
*/
36-
public function __construct(array $paths)
31+
protected function extractPath(string $path)
3732
{
38-
$this->paths = $paths;
39-
}
40-
41-
/**
42-
* Parses all metadata files and convert them in an array.
43-
*
44-
* @throws InvalidArgumentException
45-
*
46-
* @return array
47-
*/
48-
public function getResources(): array
49-
{
50-
if (null !== $this->resources) {
51-
return $this->resources;
33+
try {
34+
$xml = simplexml_import_dom(XmlUtils::loadFile($path, self::RESOURCE_SCHEMA));
35+
} catch (\InvalidArgumentException $e) {
36+
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
5237
}
5338

54-
$this->resources = [];
55-
foreach ($this->paths as $path) {
56-
try {
57-
$xml = simplexml_import_dom(XmlUtils::loadFile($path, self::RESOURCE_SCHEMA));
58-
} catch (\InvalidArgumentException $e) {
59-
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
60-
}
39+
foreach ($xml->resource as $resource) {
40+
$resourceClass = (string) $resource['class'];
6141

62-
foreach ($xml->resource as $resource) {
63-
$resourceClass = (string) $resource['class'];
64-
65-
$this->resources[$resourceClass] = [
66-
'shortName' => (string) $resource['shortName'] ?: null,
67-
'description' => (string) $resource['description'] ?: null,
68-
'iri' => (string) $resource['iri'] ?: null,
69-
'itemOperations' => $this->getAttributes($resource, 'itemOperation') ?: null,
70-
'collectionOperations' => $this->getAttributes($resource, 'collectionOperation') ?: null,
71-
'attributes' => $this->getAttributes($resource, 'attribute') ?: null,
72-
'properties' => $this->getProperties($resource, $resourceClass) ?: null,
73-
];
74-
}
42+
$this->resources[$resourceClass] = [
43+
'shortName' => (string) $resource['shortName'] ?: null,
44+
'description' => (string) $resource['description'] ?: null,
45+
'iri' => (string) $resource['iri'] ?: null,
46+
'itemOperations' => $this->getAttributes($resource, 'itemOperation') ?: null,
47+
'collectionOperations' => $this->getAttributes($resource, 'collectionOperation') ?: null,
48+
'attributes' => $this->getAttributes($resource, 'attribute') ?: null,
49+
'properties' => $this->getProperties($resource, $resourceClass) ?: null,
50+
];
7551
}
76-
77-
return $this->resources;
7852
}
7953

8054
/**

src/Metadata/YamlExtractor.php renamed to src/Metadata/Extractor/YamlExtractor.php

Lines changed: 16 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,69 +9,43 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace ApiPlatform\Core\Metadata;
12+
namespace ApiPlatform\Core\Metadata\Extractor;
1313

1414
use ApiPlatform\Core\Exception\InvalidArgumentException;
1515
use Symfony\Component\Yaml\Exception\ParseException;
1616
use Symfony\Component\Yaml\Yaml;
1717

1818
/**
19-
* Converts a list of YAML metadata files in a PHP array.
19+
* Extracts an array of metadata from a list of YAML files.
2020
*
2121
* @author Antoine Bluchet <soyuka@gmail.com>
2222
* @author Baptiste Meyer <baptiste.meyer@gmail.com>
2323
* @author Kévin Dunglas <dunglas@gmail.com>
24-
*
25-
* @internal
2624
*/
27-
final class YamlExtractor
25+
final class YamlExtractor extends AbstractExtractor
2826
{
29-
private $paths;
30-
private $resources;
31-
3227
/**
33-
* @param string[] $paths
28+
* {@inheritdoc}
3429
*/
35-
public function __construct(array $paths)
30+
protected function extractPath(string $path)
3631
{
37-
$this->paths = $paths;
38-
}
32+
try {
33+
$resourcesYaml = Yaml::parse(file_get_contents($path));
34+
} catch (ParseException $e) {
35+
$e->setParsedFile($path);
3936

40-
/**
41-
* Parses all metadata files and convert them in an array.
42-
*
43-
* @throws ParseException
44-
*
45-
* @return array
46-
*/
47-
public function getResources(): array
48-
{
49-
if (null !== $this->resources) {
50-
return $this->resources;
37+
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
5138
}
5239

53-
$this->resources = [];
54-
foreach ($this->paths as $path) {
55-
try {
56-
$resourcesYaml = Yaml::parse(file_get_contents($path));
57-
} catch (ParseException $parseException) {
58-
$parseException->setParsedFile($path);
59-
60-
throw $parseException;
61-
}
62-
63-
if (null === $resourcesYaml = $resourcesYaml['resources'] ?? $resourcesYaml) {
64-
continue;
65-
}
66-
67-
if (!is_array($resourcesYaml)) {
68-
throw new InvalidArgumentException(sprintf('"resources" setting is expected to be null or an array, %s given in "%s".', gettype($resourcesYaml), $path));
69-
}
40+
if (null === $resourcesYaml = $resourcesYaml['resources'] ?? $resourcesYaml) {
41+
return;
42+
}
7043

71-
$this->extractResources($resourcesYaml, $path);
44+
if (!is_array($resourcesYaml)) {
45+
throw new InvalidArgumentException(sprintf('"resources" setting is expected to be null or an array, %s given in "%s".', gettype($resourcesYaml), $path));
7246
}
7347

74-
return $this->resources;
48+
$this->extractResources($resourcesYaml, $path);
7549
}
7650

7751
private function extractResources(array $resourcesYaml, string $path)

src/Metadata/Property/Factory/AbstractFilePropertyMetadataFactory.php renamed to src/Metadata/Property/Factory/ExtractorPropertyMetadataFactory.php

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@
1111

1212
namespace ApiPlatform\Core\Metadata\Property\Factory;
1313

14-
use ApiPlatform\Core\Exception\InvalidArgumentException;
1514
use ApiPlatform\Core\Exception\PropertyNotFoundException;
15+
use ApiPlatform\Core\Metadata\Extractor\ExtractorInterface;
1616
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
1717

1818
/**
19-
* Common base class to load properties's metadata from files.
19+
* Creates properties's metadata using an extractor.
2020
*
2121
* @author Kévin Dunglas <dunglas@gmail.com>
22-
*
23-
* @internal
2422
*/
25-
abstract class AbstractFilePropertyMetadataFactory implements PropertyMetadataFactoryInterface
23+
final class ExtractorPropertyMetadataFactory implements PropertyMetadataFactoryInterface
2624
{
27-
protected $decorated;
25+
private $extractor;
26+
private $decorated;
2827

29-
public function __construct(PropertyMetadataFactoryInterface $decorated = null)
28+
public function __construct(ExtractorInterface $extractor, PropertyMetadataFactoryInterface $decorated = null)
3029
{
30+
$this->extractor = $extractor;
3131
$this->decorated = $decorated;
3232
}
3333

@@ -47,7 +47,7 @@ public function create(string $resourceClass, string $property, array $options =
4747

4848
if (
4949
!property_exists($resourceClass, $property) ||
50-
empty($propertyMetadata = $this->getMetadata($resourceClass, $property))
50+
!$propertyMetadata = $this->extractor->getResources()[$resourceClass]['properties'][$property] ?? false
5151
) {
5252
return $this->handleNotFound($parentPropertyMetadata, $resourceClass, $property);
5353
}
@@ -71,18 +71,6 @@ public function create(string $resourceClass, string $property, array $options =
7171
);
7272
}
7373

74-
/**
75-
* Extracts metadata.
76-
*
77-
* @param string $resourceClass
78-
* @param string $propertyName
79-
*
80-
* @throws InvalidArgumentException
81-
*
82-
* @return array
83-
*/
84-
abstract protected function getMetadata(string $resourceClass, string $propertyName): array;
85-
8674
/**
8775
* Returns the metadata from the decorated factory if available or throws an exception.
8876
*

0 commit comments

Comments
 (0)