Completed
Pull Request — master (#7)
by Théo
13:29 queued 11:14
created

DefinitionsParser::parseDefinition()   B

Complexity

Conditions 8
Paths 11

Size

Total Lines 53
Code Lines 32

Duplication

Lines 10
Ratio 18.87 %

Code Coverage

Tests 39
CRAP Score 8

Importance

Changes 4
Bugs 2 Features 2
Metric Value
dl 10
loc 53
ccs 39
cts 39
cp 1
rs 7.1199
c 4
b 2
f 2
cc 8
eloc 32
nc 11
nop 4
crap 8

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the LaravelYaml package.
5
 *
6
 * (c) Théo FIDRY <[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 Fidry\LaravelYaml\FileLoader\Parser\Yaml;
13
14
use Fidry\LaravelYaml\DependencyInjection\Builder\ContainerBuilder;
15
use Fidry\LaravelYaml\DependencyInjection\Definition\Alias;
16
use Fidry\LaravelYaml\DependencyInjection\Definition\FactoryInterface;
17
use Fidry\LaravelYaml\DependencyInjection\Definition\FactoryService;
18
use Fidry\LaravelYaml\DependencyInjection\Definition\Service;
19
use Fidry\LaravelYaml\DependencyInjection\Definition\ServiceInterface;
20
use Fidry\LaravelYaml\Exception\FileLoader\InvalidArgumentException;
21
use Fidry\LaravelYaml\FileLoader\Parser\Resolver\ResolverInterface;
22
use Fidry\LaravelYaml\FileLoader\Parser\Resolver\ServiceResolver;
23
24
/**
25
 * @author Théo FIDRY <[email protected]>
26
 */
27
final class DefinitionsParser
28
{
29
    /**
30
     * @var ResolverInterface
31
     */
32
    private $serviceResolver;
33
34 66
    public function __construct(ResolverInterface $serviceResolver = null)
35
    {
36 66
        $this->serviceResolver = (null === $serviceResolver)? new ServiceResolver(): $serviceResolver;
37 66
    }
38
39
    /**
40
     * Parses service definitions and register them to the container.
41
     *
42
     * @param ContainerBuilder $container
43
     * @param array            $content  YAML file content
44
     * @param string           $fileName file name
45
     *
46
     * @throws InvalidArgumentException
47
     */
48 66
    public function parse(ContainerBuilder $container, $content, $fileName)
49
    {
50 66
        if (!isset($content['services'])) {
51 12
            return;
52
        }
53
54 54
        if (!is_array($content['services'])) {
55 6
            throw new InvalidArgumentException(
56 2
                sprintf(
57 6
                    'The "services" key should contain an array in %s. Check your YAML syntax.',
58
                    $fileName
59 2
                )
60 2
            );
61
        }
62
63 48
        foreach ($content['services'] as $id => $service) {
64 48
            $this->parseDefinition($container, strtolower($id), $service, $fileName);
65 6
        }
66 18
    }
67
68
    /**
69
     * Parses a service definition and register it to the container.
70
     *
71
     * @param ContainerBuilder $container
72
     * @param string           $id
73
     * @param array|string     $service
74
     * @param string           $fileName file name
75
     *
76
     * @throws InvalidArgumentException
77
     */
78 48
    private function parseDefinition(ContainerBuilder $container, $id, $service, $fileName)
79
    {
80 48
        if (is_string($service) && 0 === strpos($service, '@')) {
81 6
            $alias = new Alias($id, substr($service, 1));
82 6
            $container->addAlias($alias);
83
84 6
            return;
85
        }
86
87 45 View Code Duplication
        if (false === is_array($service)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
88 3
            throw new InvalidArgumentException(
89 1
                sprintf(
90 3
                    'A service definition must be an array or a string starting with "@" but %s found for service "%s" in %s. Check your YAML syntax.',
91 1
                    gettype($service),
92 1
                    $id,
93
                    $fileName
94 1
                )
95 1
            );
96
        }
97
98 42
        if (isset($service['alias'])) {
99 12
            $aliasName = $service['alias'];
100 12
            if (false === is_string($aliasName)) {
101 3
                throw new InvalidArgumentException(
102 1
                    sprintf(
103 3
                        'Parameter "alias" must be a plain name for service "%s", but found "%s" instead in %s. Check your YAML syntax.',
104 1
                        $id,
105 1
                        gettype($aliasName),
106
                        $fileName
107 1
                    )
108 1
                );
109
            }
110
111 9
            $alias = new Alias($aliasName, $id);
112 9
            $container->addAlias($alias);
113 3
        }
114
115 39
        $class = $this->getClass($id, $service, $fileName);
116 33
        $arguments = (isset($service['arguments']))
117 13
            ? $this->serviceResolver->resolve($service['arguments'])
118 33
            : []
119 11
        ;
120 33
        $tags = $this->getTags($id, $service, $fileName);
121 21
        $autowiringTypes = $this->getAutowiringTypes($id, $service, $fileName);
122
123 15
        $serviceDefinition = new Service($id, $class, $arguments, $autowiringTypes, $tags);
124
125 15
        if (isset($service['factory'])) {
126 3
            $serviceDefinition = $this->parseFactory($serviceDefinition, $service['factory'], $fileName);
127 1
        }
128
129 15
        $container->addService($serviceDefinition);
130 15
    }
131
132
    /**
133
     * @param string $id
134
     * @param array  $service
135
     * @param string $fileName
136
     *
137
     * @return string
138
     * @throws InvalidArgumentException
139
     */
140 39
    private function getClass($id, $service, $fileName)
141
    {
142 39
        if (false === isset($service['class'])) {
143 3
            throw new InvalidArgumentException(
144 1
                sprintf(
145 3
                    'Parameter "class" missing for service "%s" in %s. Check your YAML syntax.',
146 1
                    $id,
147
                    $fileName
148 1
                )
149 1
            );
150
        }
151 36 View Code Duplication
        if (false === is_string($service['class'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152 3
            throw new InvalidArgumentException(
153 1
                sprintf(
154 3
                    'Parameter "class" must be a FQCN for service "%s", but found "%s" instead in %s. Check your YAML syntax.',
155 1
                    $id,
156 3
                    gettype($service['class']),
157
                    $fileName
158 1
                )
159 1
            );
160
        }
161
162 33
        return $service['class'];
163
    }
164
165
    /**
166
     * @param string $id
167
     * @param array  $service
168
     * @param string $fileName
169
     *
170
     * @return array
171
     * @throws InvalidArgumentException
172
     */
173 33
    private function getTags($id, $service, $fileName)
174
    {
175 33
        if (false === isset($service['tags'])) {
176 18
            return [];
177
        }
178
179 15
        $tags = [];
180 15 View Code Duplication
        if (false === is_array($service['tags'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181 3
            throw new InvalidArgumentException(
182 1
                sprintf(
183 3
                    'Parameter "tags" must be an array for service "%s" in %s. Check your YAML syntax.',
184 1
                    $id,
185
                    $fileName
186 1
                )
187 1
            );
188
        }
189
190 12
        foreach ($service['tags'] as $tag) {
191 12
            if (false === is_array($tag)) {
192 3
                throw new InvalidArgumentException(
193 1
                    sprintf(
194 3
                        'A "tags" entry must be an array for service "%s" in %s. Check your YAML syntax.',
195 1
                        $id,
196
                        $fileName
197 1
                    )
198 1
                );
199
            }
200
201 9
            if (false === isset($tag['name'])) {
202 3
                throw new InvalidArgumentException(
203 1
                    sprintf(
204 3
                        'A "tags" entry is missing a "name" key for service "%s" in %s.',
205 1
                        $id,
206
                        $fileName
207 1
                    )
208 1
                );
209
            }
210
211 6
            $name = strtolower($tag['name']);
212 6
            unset($tag['name']);
213
214 6
            foreach ($tag as $attribute => $value) {
215 3
                if (false === is_scalar($value) && null !== $value) {
216 3
                    throw new InvalidArgumentException(
217 1
                        sprintf(
218 3
                            'A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s" in %s. Check your YAML syntax.',
219 1
                            $id,
220 1
                            $name,
221 1
                            $attribute,
222
                            $fileName
223 1
                        )
224 1
                    );
225
                }
226 1
            }
227
228 3
            $tags[$name] = $tag;
229 1
        }
230
231 3
        return $tags;
232
    }
233
234
    /**
235
     * @param string $id
236
     * @param array  $service
237
     * @param string $fileName
238
     *
239
     * @return array
240
     * @throws InvalidArgumentException
241
     */
242 21
    private function getAutowiringTypes($id, $service, $fileName)
243
    {
244 21
        if (false === isset($service['autowiringTypes'])) {
245 12
            return [];
246
        }
247
248 9 View Code Duplication
        if (false === is_array($service['autowiringTypes'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
249 3
            throw new InvalidArgumentException(
250 1
                sprintf(
251 3
                    'Parameter "autowiringTypes" must be an array for service "%s" in %s. Check your YAML syntax.',
252 1
                    $id,
253
                    $fileName
254 1
                )
255 1
            );
256
        }
257
258 6
        $autowiringTypes = [];
259 6
        foreach ($service['autowiringTypes'] as $autowiringType) {
260 6
            if (false === is_string($autowiringType)) {
261 3
                throw new InvalidArgumentException(
262 1
                    sprintf(
263 3
                        'A "autowiringType" entry must be a FQCN for service "%s" in %s. Check your YAML syntax.',
264 1
                        $id,
265
                        $fileName
266 1
                    )
267 1
                );
268
            }
269
270 3
            $autowiringTypes[$autowiringType] = true;
271 1
        }
272
273 3
        return array_keys($autowiringTypes);
274
    }
275
276
    /**
277
     * Parses a factory service definition and return the factory object.
278
     *
279
     * @param ServiceInterface $service
280
     * @param mixed            $factory
281
     * @param string           $fileName file name
282
     *
283
     * @return FactoryInterface
284
     * @throws InvalidArgumentException
285
     */
286 3
    private function parseFactory( ServiceInterface $service, $factory, $fileName)
287
    {
288 3 View Code Duplication
        if (false === is_array($factory)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
289
            throw new InvalidArgumentException(
290
                sprintf(
291
                    'Parameter "factory" must be an array for service "%s", but found "%s" instead in %s. Check your YAML syntax.',
292
                    $service->getName(),
293
                    gettype($factory),
294
                    $fileName
295
                )
296
            );
297
        }
298
299 3 View Code Duplication
        if (2 !== count($factory)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
300
            throw new InvalidArgumentException(
301
                sprintf(
302
                    'Parameter "factory" expects two parameters for service "%s", but found "%s" instead in %s. Check your YAML syntax.',
303
                    $service->getName(),
304
                    gettype($factory),
305
                    $fileName
306
                )
307
            );
308
        }
309
310 3
        $factoryClass = $factory[0];
311 3
        $factoryMethod = $factory[1];
312 3 View Code Duplication
        if (false === is_string($factoryClass)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
313
            throw new InvalidArgumentException(
314
                sprintf(
315
                    'The first parameter of "factory" for service "%s" must be a class name or a reference to a service, but found "%s" instead in %s. Check your YAML syntax.',
316
                    $service->getName(),
317
                    gettype($factoryClass),
318
                    $fileName
319
                )
320
            );
321
        }
322 3
        $factoryClass = $this->serviceResolver->resolve($factoryClass);
323
324 3 View Code Duplication
        if (false === is_string($factoryMethod)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
325
            throw new InvalidArgumentException(
326
                sprintf(
327
                    'The second parameter of "factory" for service "%s" must be a class name or a reference to a service, but found "%s" instead in %s. Check your YAML syntax.',
328
                    $service->getName(),
329
                    gettype($factoryMethod),
330
                    $fileName
331
                )
332
            );
333
        }
334
335 3
       return new FactoryService($service, $factoryClass, $factoryMethod);
336
    }
337
}
338