Completed
Push — master ( 3ae770...b31906 )
by Théo
19:43 queued 07:06
created

DefinitionsParser::parseFactory()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 51
Code Lines 33

Duplication

Lines 40
Ratio 78.43 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 40
loc 51
ccs 0
cts 0
cp 0
rs 8.6588
cc 5
eloc 33
nc 5
nop 3
crap 30

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 63
     */
32
    private $serviceResolver;
33 63
34 63
    public function __construct(ResolverInterface $serviceResolver = null)
35
    {
36
        $this->serviceResolver = (null === $serviceResolver)? new ServiceResolver(): $serviceResolver;
37
    }
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 63
     *
46
     * @throws InvalidArgumentException
47 63
     */
48 12
    public function parse(ContainerBuilder $container, $content, $fileName)
49
    {
50
        if (!isset($content['services'])) {
51 51
            return;
52 6
        }
53 4
54 6
        if (!is_array($content['services'])) {
55
            throw new InvalidArgumentException(
56 4
                sprintf(
57 4
                    'The "services" key should contain an array in %s. Check your YAML syntax.',
58
                    $fileName
59
                )
60 45
            );
61 45
        }
62 10
63 15
        foreach ($content['services'] as $id => $service) {
64
            $this->parseDefinition($container, strtolower($id), $service, $fileName);
65
        }
66
    }
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 45
     *
76
     * @throws InvalidArgumentException
77 45
     */
78 6
    private function parseDefinition(ContainerBuilder $container, $id, $service, $fileName)
79 6
    {
80
        if (is_string($service) && 0 === strpos($service, '@')) {
81 6
            $alias = new Alias($id, substr($service, 1));
82
            $container->addAlias($alias);
83
84 42
            return;
85 3
        }
86 2
87 3 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 2
            throw new InvalidArgumentException(
89 2
                sprintf(
90
                    '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 2
                    gettype($service),
92 2
                    $id,
93
                    $fileName
94
                )
95 39
            );
96 12
        }
97 12
98 3
        if (isset($service['alias'])) {
99 2
            $aliasName = $service['alias'];
100 3
            if (false === is_string($aliasName)) {
101 2
                throw new InvalidArgumentException(
102 2
                    sprintf(
103
                        'Parameter "alias" must be a plain name for service "%s", but found "%s" instead in %s. Check your YAML syntax.',
104 2
                        $id,
105 2
                        gettype($aliasName),
106
                        $fileName
107
                    )
108 9
                );
109 9
            }
110 6
111
            $alias = new Alias($aliasName, $id);
112 36
            $container->addAlias($alias);
113 30
        }
114 21
115 30
        $class = $this->getClass($id, $service, $fileName);
116 20
        $arguments = (isset($service['arguments']))
117 30
            ? $this->serviceResolver->resolve($service['arguments'])
118 18
            : []
119
        ;
120 12
        $tags = $this->getTags($id, $service, $fileName);
121 12
        $autowiringTypes = $this->getAutowiringTypes($id, $service, $fileName);
122 12
123
        $serviceDefinition = new Service($id, $class, $arguments, $autowiringTypes, $tags);
124
125
        if (isset($service['factory'])) {
126
            $serviceDefinition = $this->parseFactory($serviceDefinition, $service['factory'], $fileName);
127
        }
128
129
        $container->addService($serviceDefinition);
130
    }
131
132 36
    /**
133
     * @param string $id
134 36
     * @param array  $service
135 3
     * @param string $fileName
136 2
     *
137 3
     * @return string
138 2
     * @throws InvalidArgumentException
139
     */
140 2
    private function getClass($id, $service, $fileName)
141 2
    {
142
        if (false === isset($service['class'])) {
143 33
            throw new InvalidArgumentException(
144 3
                sprintf(
145 2
                    'Parameter "class" missing for service "%s" in %s. Check your YAML syntax.',
146 3
                    $id,
147 2
                    $fileName
148 3
                )
149
            );
150 2
        }
151 2 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
            throw new InvalidArgumentException(
153
                sprintf(
154 30
                    'Parameter "class" must be a FQCN for service "%s", but found "%s" instead in %s. Check your YAML syntax.',
155
                    $id,
156
                    gettype($service['class']),
157
                    $fileName
158
                )
159
            );
160
        }
161
162
        return $service['class'];
163
    }
164
165 30
    /**
166
     * @param string $id
167 30
     * @param array  $service
168 15
     * @param string $fileName
169
     *
170
     * @return array
171 15
     * @throws InvalidArgumentException
172 15
     */
173 3
    private function getTags($id, $service, $fileName)
174 2
    {
175 3
        if (false === isset($service['tags'])) {
176 2
            return [];
177
        }
178 2
179 2
        $tags = [];
180 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
            throw new InvalidArgumentException(
182 12
                sprintf(
183 12
                    'Parameter "tags" must be an array for service "%s" in %s. Check your YAML syntax.',
184 3
                    $id,
185 2
                    $fileName
186 3
                )
187 2
            );
188
        }
189 2
190 2
        foreach ($service['tags'] as $tag) {
191
            if (false === is_array($tag)) {
192
                throw new InvalidArgumentException(
193 9
                    sprintf(
194 3
                        'A "tags" entry must be an array for service "%s" in %s. Check your YAML syntax.',
195 2
                        $id,
196 3
                        $fileName
197 2
                    )
198
                );
199 2
            }
200 2
201
            if (false === isset($tag['name'])) {
202
                throw new InvalidArgumentException(
203 6
                    sprintf(
204 6
                        'A "tags" entry is missing a "name" key for service "%s" in %s.',
205
                        $id,
206 6
                        $fileName
207 3
                    )
208 3
                );
209 2
            }
210 3
211 2
            $name = strtolower($tag['name']);
212 2
            unset($tag['name']);
213 2
214
            foreach ($tag as $attribute => $value) {
215 2
                if (false === is_scalar($value) && null !== $value) {
216 2
                    throw new InvalidArgumentException(
217
                        sprintf(
218 2
                            'A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s" in %s. Check your YAML syntax.',
219
                            $id,
220 3
                            $name,
221 2
                            $attribute,
222
                            $fileName
223 3
                        )
224
                    );
225
                }
226
            }
227
228
            $tags[$name] = $tag;
229
        }
230
231
        return $tags;
232
    }
233
234 18
    /**
235
     * @param string $id
236 18
     * @param array  $service
237 9
     * @param string $fileName
238
     *
239
     * @return array
240 9
     * @throws InvalidArgumentException
241 3
     */
242 2
    private function getAutowiringTypes($id, $service, $fileName)
243 3
    {
244 2
        if (false === isset($service['autowiringTypes'])) {
245
            return [];
246 2
        }
247 2
248 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
            throw new InvalidArgumentException(
250 6
                sprintf(
251 6
                    'Parameter "autowiringTypes" must be an array for service "%s" in %s. Check your YAML syntax.',
252 6
                    $id,
253 3
                    $fileName
254 2
                )
255 3
            );
256 2
        }
257
258 2
        $autowiringTypes = [];
259 2
        foreach ($service['autowiringTypes'] as $autowiringType) {
260
            if (false === is_string($autowiringType)) {
261
                throw new InvalidArgumentException(
262 3
                    sprintf(
263 2
                        'A "autowiringType" entry must be a FQCN for service "%s" in %s. Check your YAML syntax.',
264
                        $id,
265 3
                        $fileName
266
                    )
267
                );
268
            }
269
270
            $autowiringTypes[$autowiringType] = true;
271
        }
272
273
        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
    private function parseFactory( ServiceInterface $service, $factory, $fileName)
287
    {
288 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 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
        $factoryClass = $factory[0];
311
        $factoryMethod = $factory[1];
312 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
        $factoryClass = $this->serviceResolver->resolve($factoryClass);
323
324 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
       return new FactoryService($service, $factoryClass, $factoryMethod);
336
    }
337
}
338