Skip to content

Commit 0ecd217

Browse files
authored
Merge pull request #837 from dunglas/factory_refactoring
Refactor and merge YAML and XML loaders
2 parents 87e2f4c + 20a360e commit 0ecd217

File tree

46 files changed

+1332
-1797
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1332
-1797
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ high performance API-first projects. Extend or override everything you want.
1414
[![Build Status](https://travis-ci.org/api-platform/core.svg?branch=master)](https://travis-ci.org/api-platform/core)
1515
[![Build status](https://ci.appveyor.com/api/projects/status/grwuyprts3wdqx5l?svg=true)](https://ci.appveyor.com/project/dunglas/dunglasapibundle)
1616
[![Coverage Status](https://coveralls.io/repos/github/api-platform/core/badge.svg)](https://coveralls.io/github/api-platform/core)
17-
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/a93f5a40-483f-4c46-ba09-3e1033b62552/mini.png)](https://insight.sensiolabs.com/projects/a93f5a40-483f-4c46-ba09-3e1033b62552)
17+
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/92d78899-946c-4282-89a3-ac92344f9a93/mini.png)](https://insight.sensiolabs.com/projects/92d78899-946c-4282-89a3-ac92344f9a93)
1818
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/api-platform/core/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/api-platform/core/?branch=master)
1919
[![Dependency Status](https://www.versioneye.com/user/projects/5552e93306c318a32a0000fa/badge.svg?style=flat)](https://www.versioneye.com/user/projects/5552e93306c318a32a0000fa)
2020

features/configurable.feature

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ Feature: Configurable resource CRUD
1919
{
2020
"@id": "/fileconfigdummies/1",
2121
"@type": "fileconfigdummy",
22-
"foo": "Foo",
2322
"id": 1,
24-
"name": "ConfigDummy"
23+
"name": "ConfigDummy",
24+
"foo": "Foo"
2525
}
2626
],
2727
"hydra:totalItems": 1
@@ -53,11 +53,11 @@ Feature: Configurable resource CRUD
5353
And the JSON should be equal to:
5454
"""
5555
{
56-
"@context": "\/contexts\/fileconfigdummy",
57-
"@id": "\/fileconfigdummies\/1",
58-
"@type": "fileconfigdummy",
59-
"foo": "Foo",
60-
"id": 1,
61-
"name": "ConfigDummy"
62-
}
56+
"@context": "/contexts/fileconfigdummy",
57+
"@id": "/fileconfigdummies/1",
58+
"@type": "fileconfigdummy",
59+
"id": 1,
60+
"name": "ConfigDummy",
61+
"foo": "Foo"
62+
}
6363
"""

src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -261,18 +261,8 @@ private function registerLoaders(ContainerBuilder $container, array $bundles)
261261
}
262262

263263
$container->getDefinition('api_platform.metadata.resource.name_collection_factory.annotation')->addArgument($annotationPaths);
264-
265-
$container->getDefinition('api_platform.metadata.resource.name_collection_factory.yaml')->replaceArgument(0, $yamlResources);
266-
$container->getDefinition('api_platform.metadata.resource.metadata_factory.yaml')->replaceArgument(0, $yamlResources);
267-
268-
$container->getDefinition('api_platform.metadata.property.name_collection_factory.yaml')->replaceArgument(0, $yamlResources);
269-
$container->getDefinition('api_platform.metadata.property.metadata_factory.yaml')->replaceArgument(0, $yamlResources);
270-
271-
$container->getDefinition('api_platform.metadata.resource.name_collection_factory.xml')->replaceArgument(0, $xmlResources);
272-
$container->getDefinition('api_platform.metadata.resource.metadata_factory.xml')->replaceArgument(0, $xmlResources);
273-
274-
$container->getDefinition('api_platform.metadata.property.name_collection_factory.xml')->replaceArgument(0, $xmlResources);
275-
$container->getDefinition('api_platform.metadata.property.metadata_factory.xml')->replaceArgument(0, $xmlResources);
264+
$container->getDefinition('api_platform.metadata.extractor.yaml')->addArgument($yamlResources);
265+
$container->getDefinition('api_platform.metadata.extractor.xml')->addArgument($xmlResources);
276266
}
277267

278268
/**

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
66

77
<services>
8+
9+
<!-- Extractor -->
10+
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" />
13+
814
<!-- Resource name collection -->
915

1016
<service id="api_platform.metadata.resource.name_collection_factory" alias="api_platform.metadata.resource.name_collection_factory.annotation" />
@@ -18,14 +24,14 @@
1824
<argument type="service" id="api_platform.metadata.resource.name_collection_factory.cached.inner" />
1925
</service>
2026

21-
<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">
22-
<argument type="collection" />
23-
<argument type="service" id="api_platform.metadata.resource.name_collection_factory.yaml.inner" />
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">
28+
<argument type="service" id="api_platform.metadata.extractor.yaml" />
29+
<argument type="service" id="api_platform.metadata.resource.name_collection_factory.yaml.inner" />
2430
</service>
2531

26-
<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">
27-
<argument type="collection" />
28-
<argument type="service" id="api_platform.metadata.resource.name_collection_factory.xml.inner" />
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">
33+
<argument type="service" id="api_platform.metadata.extractor.xml" />
34+
<argument type="service" id="api_platform.metadata.resource.name_collection_factory.xml.inner" />
2935
</service>
3036

3137
<!-- Resource metadata -->
@@ -40,13 +46,13 @@
4046
<argument type="service" id="api_platform.metadata.resource.metadata_factory.php_doc.inner" />
4147
</service>
4248

43-
<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">
44-
<argument type="collection" />
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">
50+
<argument type="service" id="api_platform.metadata.extractor.yaml" />
4551
<argument type="service" id="api_platform.metadata.resource.metadata_factory.yaml.inner" />
4652
</service>
4753

48-
<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">
49-
<argument type="collection" />
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">
55+
<argument type="service" id="api_platform.metadata.extractor.xml" />
5056
<argument type="service" id="api_platform.metadata.resource.metadata_factory.xml.inner" />
5157
</service>
5258

@@ -89,13 +95,13 @@
8995
<argument type="service" id="api_platform.metadata.property.name_collection_factory.cached.inner" />
9096
</service>
9197

92-
<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">
93-
<argument type="collection" />
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">
99+
<argument type="service" id="api_platform.metadata.extractor.yaml" />
94100
<argument type="service" id="api_platform.metadata.property.name_collection_factory.yaml.inner" />
95101
</service>
96102

97-
<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">
98-
<argument type="collection" />
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">
104+
<argument type="service" id="api_platform.metadata.extractor.xml" />
99105
<argument type="service" id="api_platform.metadata.property.name_collection_factory.xml.inner" />
100106
</service>
101107

@@ -118,13 +124,13 @@
118124
<argument type="service" id="api_platform.metadata.property.metadata_factory.inherited.inner" />
119125
</service>
120126

121-
<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">
122-
<argument type="collection" />
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">
128+
<argument type="service" id="api_platform.metadata.extractor.yaml" />
123129
<argument type="service" id="api_platform.metadata.property.metadata_factory.yaml.inner" />
124130
</service>
125131

126-
<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">
127-
<argument type="collection" />
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">
133+
<argument type="service" id="api_platform.metadata.extractor.xml" />
128134
<argument type="service" id="api_platform.metadata.property.metadata_factory.xml.inner" />
129135
</service>
130136

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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
use Symfony\Component\Config\Util\XmlUtils;
16+
17+
/**
18+
* Extracts an array of metadata from a list of XML files.
19+
*
20+
* @author Kévin Dunglas <[email protected]>
21+
* @author Antoine Bluchet <[email protected]>
22+
* @author Baptiste Meyer <[email protected]>
23+
*/
24+
final class XmlExtractor extends AbstractExtractor
25+
{
26+
const RESOURCE_SCHEMA = __DIR__.'/../schema/metadata.xsd';
27+
28+
/**
29+
* {@inheritdoc}
30+
*/
31+
protected function extractPath(string $path)
32+
{
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);
37+
}
38+
39+
foreach ($xml->resource as $resource) {
40+
$resourceClass = (string) $resource['class'];
41+
42+
$this->resources[$resourceClass] = [
43+
'shortName' => $this->phpize($resource, 'shortName', 'string'),
44+
'description' => $this->phpize($resource, 'description', 'string'),
45+
'iri' => $this->phpize($resource, 'iri', 'string'),
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) ?: null,
50+
];
51+
}
52+
}
53+
54+
/**
55+
* Recursively transforms an attribute structure into an associative array.
56+
*
57+
* @param \SimpleXMLElement $resource
58+
* @param string $elementName
59+
*
60+
* @return array
61+
*/
62+
private function getAttributes(\SimpleXMLElement $resource, string $elementName): array
63+
{
64+
$attributes = [];
65+
foreach ($resource->$elementName as $attribute) {
66+
if (isset($attribute->attribute[0])) {
67+
$value = $this->getAttributes($attribute, 'attribute');
68+
} else {
69+
$value = (string) $attribute;
70+
}
71+
72+
if (isset($attribute['name'])) {
73+
$attributes[(string) $attribute['name']] = $value;
74+
} else {
75+
$attributes[] = $value;
76+
}
77+
}
78+
79+
return $attributes;
80+
}
81+
82+
/**
83+
* Gets metadata of a property.
84+
*
85+
* @param \SimpleXMLElement $resource
86+
*
87+
* @return array
88+
*/
89+
private function getProperties(\SimpleXMLElement $resource): array
90+
{
91+
$properties = [];
92+
foreach ($resource->property as $property) {
93+
$properties[(string) $property['name']] = [
94+
'description' => $this->phpize($property, 'description', 'string'),
95+
'readable' => $this->phpize($property, 'readable', 'bool'),
96+
'writable' => $this->phpize($property, 'writable', 'bool'),
97+
'readableLink' => $this->phpize($property, 'readableLink', 'bool'),
98+
'writableLink' => $this->phpize($property, 'writableLink', 'bool'),
99+
'required' => $this->phpize($property, 'required', 'bool'),
100+
'identifier' => $this->phpize($property, 'identifier', 'bool'),
101+
'iri' => $this->phpize($property, 'iri', 'string'),
102+
'attributes' => $this->getAttributes($property, 'attribute'),
103+
];
104+
}
105+
106+
return $properties;
107+
}
108+
109+
/**
110+
* Transforms an XML attribute's value in a PHP value.
111+
*
112+
* @param \SimpleXMLElement $array
113+
* @param string $key
114+
* @param string $type
115+
*
116+
* @return bool|string|null
117+
*/
118+
private function phpize(\SimpleXMLElement $array, string $key, string $type)
119+
{
120+
if (!isset($array[$key])) {
121+
return;
122+
}
123+
124+
switch ($type) {
125+
case 'string':
126+
return (string) $array[$key];
127+
128+
case 'bool':
129+
return (bool) XmlUtils::phpize($array[$key]);
130+
}
131+
}
132+
}

0 commit comments

Comments
 (0)