Completed
Push — master ( a2ccb4...2afc29 )
by Philip
05:08
created

Metadata/Driver/YamlDriver.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Dontdrinkandroot\RestBundle\Metadata\Driver;
4
5
use Dontdrinkandroot\RestBundle\Metadata\Annotation\Method;
6
use Dontdrinkandroot\RestBundle\Metadata\Annotation\Postable;
7
use Dontdrinkandroot\RestBundle\Metadata\Annotation\Puttable;
8
use Dontdrinkandroot\RestBundle\Metadata\ClassMetadata;
9
use Dontdrinkandroot\RestBundle\Metadata\PropertyMetadata;
10
use Metadata\Driver\AbstractFileDriver;
11
use Metadata\Driver\DriverInterface;
12
use Metadata\Driver\FileLocatorInterface;
13
use Symfony\Component\Yaml\Yaml;
14
15
class YamlDriver extends AbstractFileDriver
16
{
17
    /**
18
     * @var DriverInterface
19
     */
20
    private $doctrineDriver;
21
22 88
    public function __construct(FileLocatorInterface $locator, DriverInterface $doctrineDriver)
23
    {
24 88
        parent::__construct($locator);
25 88
        $this->doctrineDriver = $doctrineDriver;
26 88
    }
27
28
    /**
29
     * {@inheritdoc}
30
     */
31 52
    protected function loadMetadataFromFile(\ReflectionClass $class, $file)
32
    {
33
        /** @var ClassMetadata $ddrRestClassMetadata */
34 52
        $classMetadata = $this->doctrineDriver->loadMetadataForClass($class);
35 52
        if (null === $classMetadata) {
36
            $classMetadata = new ClassMetadata($class->getName());
37
        }
38
39 52
        $config = Yaml::parse(file_get_contents($file));
40 52
        $className = key($config);
41
42 52
        if ($className !== $class->name) {
43
            throw new \RuntimeException(
44
                sprintf('Class definition mismatch for "%s" in "%s": %s', $class->getName(), $file, key($config))
45
            );
46
        }
47
48 52
        $config = $config[$className];
49 52
        if (!is_array($config)) {
50
            $config = [];
51
        }
52
53 52
        if (array_key_exists('rootResource', $config) && true === $config['rootResource']) {
54 52
            $classMetadata->setRestResource(true);
55
        }
56 52
        if (array_key_exists('service', $config)) {
57 12
            $classMetadata->service = $config['service'];
58
        }
59 52
        if (array_key_exists('controller', $config)) {
60
            $classMetadata->controller = $config['controller'];
61
        }
62 52
        if (array_key_exists('idField', $config)) {
63
            $classMetadata->idField = $config['idField'];
64
        }
65 52
        if (array_key_exists('pathPrefix', $config)) {
66
            $classMetadata->pathPrefix = $config['pathPrefix'];
67
        }
68 52
        if (array_key_exists('namePrefix', $config)) {
69
            $classMetadata->namePrefix = $config['namePrefix'];
70
        }
71
72 52
        $classMetadata->setMethods($this->parseMethods($config));
73
74 52
        $fieldConfigs = [];
75 52
        if (array_key_exists('fields', $config)) {
76 52
            $fieldConfigs = $config['fields'];
77
        }
78
79 52
        foreach ($class->getProperties() as $reflectionProperty) {
80
81 52
            $propertyName = $reflectionProperty->getName();
82 52
            $propertyMetadata = $this->getOrCreatePropertymetadata($classMetadata, $propertyName);
83
84 52
            if (array_key_exists($propertyName, $fieldConfigs)) {
85 52
                $fieldConfig = $fieldConfigs[$propertyName];
86 52
                $this->parseFieldConfig($propertyName, $fieldConfig, $propertyMetadata);
87 52
                unset($fieldConfigs[$propertyName]);
88
            }
89
90 52
            $classMetadata->addPropertyMetadata($propertyMetadata);
91
        }
92
93
        /* Parse unbacked field definitions */
94 52
        foreach ($fieldConfigs as $name => $fieldConfig) {
95 32
            $propertyMetadata = $this->getOrCreatePropertymetadata($classMetadata, $name);
96 32
            $this->parseFieldConfig($name, $fieldConfig, $propertyMetadata);
97 32
            $classMetadata->addPropertyMetadata($propertyMetadata);
98
        }
99
100 52
        return $classMetadata;
101
    }
102
103 52
    protected function parseFieldConfig(string $name, array $fieldConfig, PropertyMetadata $propertyMetadata): void
104
    {
105 52
        $propertyMetadata->setPostable(Postable::parse($fieldConfig['postable'] ?? null));
106 52
        $propertyMetadata->setPuttable(Puttable::parse($fieldConfig['puttable'] ?? null));
107
108 52
        if (null !== $value = $this->getBool('excluded', $fieldConfig)) {
109 32
            $propertyMetadata->setExcluded($value);
110
        }
111
112 52
        if (null !== $value = $this->getBool('virtual', $fieldConfig)) {
113 30
            $propertyMetadata->setVirtual($value);
114
        }
115
116 52
        if (null !== $subResourceConfig = $fieldConfig['subResource'] ?? null) {
117 50
            $propertyMetadata->setSubResource(true);
118 50
            $propertyMetadata->setMethods($this->parseMethods($subResourceConfig));
0 ignored issues
show
$this->parseMethods($subResourceConfig) is of type null|array, but the function expects a array<integer,object<Don...ata\Annotation\Method>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
119
        }
120
121 52
        if (array_key_exists('includable', $fieldConfig)) {
122 50
            $value = $fieldConfig['includable'];
123 50
            if (is_array($value)) {
124 32
                $propertyMetadata->setIncludable(true);
125 32
                $propertyMetadata->setIncludablePaths($value);
126 50
            } elseif (true === $value) {
127 50
                $propertyMetadata->setIncludable(true);
128 50
                $propertyMetadata->setIncludablePaths([$name]);
129
            }
130
        }
131 52
    }
132
133 52
    private function getBool(string $key, array $haystack, bool $required = false)
134
    {
135 52
        $value = $this->getArrayValue($key, $haystack, $required);
136 52
        if (null === $value) {
137 52
            return null;
138
        }
139
140 32
        if (!is_bool($value)) {
141
            throw new \RuntimeException(sprintf('Value %s must be of type bool', $key));
142
        }
143
144 32
        return $value;
145
    }
146
147 52
    private function getArrayValue(string $key, array $haystack, bool $required = false)
148
    {
149 52
        if (!array_key_exists($key, $haystack)) {
150 52
            if ($required) {
151
                throw new \RuntimeException(sprintf('Value %s is required', $key));
152
            }
153
154 52
            return null;
155
        }
156
157 32
        return $haystack[$key];
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163 88
    protected function getExtension()
164
    {
165 88
        return 'rest.yml';
166
    }
167
168 52
    protected function getOrCreatePropertymetadata(ClassMetadata $classMetadata, $propertyName): PropertyMetadata
169
    {
170 52
        $propertyMetadata = $classMetadata->getPropertyMetadata($propertyName);
171 52
        if (null === $propertyMetadata) {
172 32
            $propertyMetadata = new PropertyMetadata($classMetadata->name, $propertyName);
173
174 32
            return $propertyMetadata;
175
        }
176
177 50
        return $propertyMetadata;
178
    }
179
180
    /**
181
     * @param array $config
182
     *
183
     * @return Method[]
184
     */
185 52
    private function parseMethods(array $config)
186
    {
187 52
        if (!array_key_exists('methods', $config)) {
188
            return null;
189
        }
190
191 52
        $methods = [];
192 52
        $methodsConfig = $config['methods'];
193 52
        foreach ($methodsConfig as $name => $config) {
194 52
            $method = Method::parse($name, $config);
195 52
            $methods[$method->name] = $method;
196
        }
197
198 52
        return $methods;
199
    }
200
}
201