Completed
Push — master ( 9d3813...8b213d )
by Kévin
11s
created

XmlExtractor::extractPath()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 8.6737
c 0
b 0
f 0
cc 5
eloc 15
nc 6
nop 1
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->getOperations($resource, 'itemOperation'),
47
                'collectionOperations' => $this->getOperations($resource, 'collectionOperation'),
48
                'attributes' => $this->getAttributes($resource, 'attribute') ?: null,
49
                'properties' => $this->getProperties($resource) ?: null,
50
            ];
51
        }
52
    }
53
54
    /**
55
     * Return the array containing configured operations. Returns NULL if there is no operation configuration.
56
     *
57
     * @param \SimpleXMLElement $resource
58
     * @param string            $operationType
59
     *
60
     * @return array|null
61
     */
62
    private function getOperations(\SimpleXMLElement $resource, string $operationType)
63
    {
64
        if ($legacyOperations = $this->getAttributes($resource, $operationType)) {
65
            @trigger_error(
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
66
                sprintf('Configuring "%1$s" tags without using a parent "%1$ss" tag is deprecrated since API Platform 2.1 and will not be possible anymore in API Platform 3', $operationType),
67
                E_USER_DEPRECATED
68
            );
69
70
            return $legacyOperations;
71
        }
72
73
        $operationsParent = $operationType.'s';
74
75
        if (!isset($resource->$operationsParent)) {
76
            return;
77
        }
78
79
        return $this->getAttributes($resource->$operationsParent, $operationType);
80
    }
81
82
    /**
83
     * Recursively transforms an attribute structure into an associative array.
84
     *
85
     * @param \SimpleXMLElement $resource
86
     * @param string            $elementName
87
     *
88
     * @return array
89
     */
90
    private function getAttributes(\SimpleXMLElement $resource, string $elementName): array
91
    {
92
        $attributes = [];
93
        foreach ($resource->$elementName as $attribute) {
94
            if (isset($attribute->attribute[0])) {
95
                $value = $this->getAttributes($attribute, 'attribute');
96
            } else {
97
                $value = XmlUtils::phpize($attribute);
98
            }
99
100
            if (isset($attribute['name'])) {
101
                $attributes[(string) $attribute['name']] = $value;
102
            } else {
103
                $attributes[] = $value;
104
            }
105
        }
106
107
        return $attributes;
108
    }
109
110
    /**
111
     * Gets metadata of a property.
112
     *
113
     * @param \SimpleXMLElement $resource
114
     *
115
     * @return array
116
     */
117
    private function getProperties(\SimpleXMLElement $resource): array
118
    {
119
        $properties = [];
120
        foreach ($resource->property as $property) {
121
            $properties[(string) $property['name']] = [
122
                'description' => $this->phpize($property, 'description', 'string'),
123
                'readable' => $this->phpize($property, 'readable', 'bool'),
124
                'writable' => $this->phpize($property, 'writable', 'bool'),
125
                'readableLink' => $this->phpize($property, 'readableLink', 'bool'),
126
                'writableLink' => $this->phpize($property, 'writableLink', 'bool'),
127
                'required' => $this->phpize($property, 'required', 'bool'),
128
                'identifier' => $this->phpize($property, 'identifier', 'bool'),
129
                'iri' => $this->phpize($property, 'iri', 'string'),
130
                'attributes' => $this->getAttributes($property, 'attribute'),
131
            ];
132
        }
133
134
        return $properties;
135
    }
136
137
    /**
138
     * Transforms an XML attribute's value in a PHP value.
139
     *
140
     * @param \SimpleXMLElement $array
141
     * @param string            $key
142
     * @param string            $type
143
     *
144
     * @return bool|string|null
145
     */
146
    private function phpize(\SimpleXMLElement $array, string $key, string $type)
147
    {
148
        if (!isset($array[$key])) {
149
            return;
150
        }
151
152
        switch ($type) {
153
            case 'string':
154
                return (string) $array[$key];
155
156
            case 'bool':
157
                return (bool) XmlUtils::phpize($array[$key]);
158
        }
159
    }
160
}
161