YamlDumper::addService()   F
last analyzed

Complexity

Conditions 23
Paths > 20000

Size

Total Lines 89
Code Lines 48

Duplication

Lines 6
Ratio 6.74 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 6
loc 89
rs 2
cc 23
eloc 48
nc 1179648
nop 2

How to fix   Long Method    Complexity   

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 Symfony package.
5
 *
6
 * (c) Fabien Potencier <[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 Symfony\Component\DependencyInjection\Dumper;
13
14
use Symfony\Component\Yaml\Dumper as YmlDumper;
15
use Symfony\Component\DependencyInjection\Alias;
16
use Symfony\Component\DependencyInjection\ContainerInterface;
17
use Symfony\Component\DependencyInjection\Definition;
18
use Symfony\Component\DependencyInjection\Parameter;
19
use Symfony\Component\DependencyInjection\Reference;
20
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
21
use Symfony\Component\ExpressionLanguage\Expression;
22
23
/**
24
 * YamlDumper dumps a service container as a YAML string.
25
 *
26
 * @author Fabien Potencier <[email protected]>
27
 *
28
 * @api
29
 */
30
class YamlDumper extends Dumper
31
{
32
    private $dumper;
33
34
    /**
35
     * Dumps the service container as an YAML string.
36
     *
37
     * @param array $options An array of options
38
     *
39
     * @return string A YAML string representing of the service container
40
     *
41
     * @api
42
     */
43
    public function dump(array $options = array())
44
    {
45
        if (!class_exists('Symfony\Component\Yaml\Dumper')) {
46
            throw new RuntimeException('Unable to dump the container as the Symfony Yaml Component is not installed.');
47
        }
48
49
        if (null === $this->dumper) {
50
            $this->dumper = new YmlDumper();
51
        }
52
53
        return $this->addParameters()."\n".$this->addServices();
54
    }
55
56
    /**
57
     * Adds a service.
58
     *
59
     * @param string     $id
60
     * @param Definition $definition
61
     *
62
     * @return string
63
     */
64
    private function addService($id, $definition)
65
    {
66
        $code = "    $id:\n";
67
        if ($definition->getClass()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $definition->getClass() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
68
            $code .= sprintf("        class: %s\n", $definition->getClass());
69
        }
70
71
        if (!$definition->isPublic()) {
72
            $code .= "        public: false\n";
73
        }
74
75
        $tagsCode = '';
76
        foreach ($definition->getTags() as $name => $tags) {
77
            foreach ($tags as $attributes) {
78
                $att = array();
79
                foreach ($attributes as $key => $value) {
80
                    $att[] = sprintf('%s: %s', $this->dumper->dump($key), $this->dumper->dump($value));
81
                }
82
                $att = $att ? ', '.implode(', ', $att) : '';
83
84
                $tagsCode .= sprintf("            - { name: %s%s }\n", $this->dumper->dump($name), $att);
85
            }
86
        }
87
        if ($tagsCode) {
88
            $code .= "        tags:\n".$tagsCode;
89
        }
90
91
        if ($definition->getFile()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $definition->getFile() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
92
            $code .= sprintf("        file: %s\n", $definition->getFile());
93
        }
94
95
        if ($definition->isSynthetic()) {
96
            $code .= sprintf("        synthetic: true\n");
97
        }
98
99
        if ($definition->isSynchronized(false)) {
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Depend...ition::isSynchronized() has been deprecated with message: since version 2.7, will be removed in 3.0.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
100
            $code .= sprintf("        synchronized: true\n");
101
        }
102
103
        if ($definition->getFactoryClass(false)) {
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Depend...tion::getFactoryClass() has been deprecated with message: since version 2.6, to be removed in 3.0.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
Bug Best Practice introduced by
The expression $definition->getFactoryClass(false) of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
104
            $code .= sprintf("        factory_class: %s\n", $definition->getFactoryClass(false));
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Depend...tion::getFactoryClass() has been deprecated with message: since version 2.6, to be removed in 3.0.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
105
        }
106
107
        if ($definition->isLazy()) {
108
            $code .= sprintf("        lazy: true\n");
109
        }
110
111
        if ($definition->getFactoryMethod(false)) {
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Depend...ion::getFactoryMethod() has been deprecated with message: since version 2.6, to be removed in 3.0.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
Bug Best Practice introduced by
The expression $definition->getFactoryMethod(false) of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
112
            $code .= sprintf("        factory_method: %s\n", $definition->getFactoryMethod(false));
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Depend...ion::getFactoryMethod() has been deprecated with message: since version 2.6, to be removed in 3.0.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
113
        }
114
115
        if ($definition->getFactoryService(false)) {
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Depend...on::getFactoryService() has been deprecated with message: since version 2.6, to be removed in 3.0.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
Bug Best Practice introduced by
The expression $definition->getFactoryService(false) of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
116
            $code .= sprintf("        factory_service: %s\n", $definition->getFactoryService(false));
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Depend...on::getFactoryService() has been deprecated with message: since version 2.6, to be removed in 3.0.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
117
        }
118
119
        if ($definition->getArguments()) {
120
            $code .= sprintf("        arguments: %s\n", $this->dumper->dump($this->dumpValue($definition->getArguments()), 0));
121
        }
122
123
        if ($definition->getProperties()) {
124
            $code .= sprintf("        properties: %s\n", $this->dumper->dump($this->dumpValue($definition->getProperties()), 0));
125
        }
126
127
        if ($definition->getMethodCalls()) {
128
            $code .= sprintf("        calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12));
129
        }
130
131
        if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
132
            $code .= sprintf("        scope: %s\n", $scope);
133
        }
134
135
        if (null !== $decorated = $definition->getDecoratedService()) {
136
            list($decorated, $renamedId) = $decorated;
137
            $code .= sprintf("        decorates: %s\n", $decorated);
138
            if (null !== $renamedId) {
139
                $code .= sprintf("        decoration_inner_name: %s\n", $renamedId);
140
            }
141
        }
142
143 View Code Duplication
        if ($callable = $definition->getFactory()) {
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...
144
            $code .= sprintf("        factory: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0));
145
        }
146
147 View Code Duplication
        if ($callable = $definition->getConfigurator()) {
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...
148
            $code .= sprintf("        configurator: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0));
149
        }
150
151
        return $code;
152
    }
153
154
    /**
155
     * Adds a service alias.
156
     *
157
     * @param string $alias
158
     * @param Alias  $id
159
     *
160
     * @return string
161
     */
162
    private function addServiceAlias($alias, $id)
163
    {
164
        if ($id->isPublic()) {
165
            return sprintf("    %s: @%s\n", $alias, $id);
166
        } else {
167
            return sprintf("    %s:\n        alias: %s\n        public: false", $alias, $id);
168
        }
169
    }
170
171
    /**
172
     * Adds services.
173
     *
174
     * @return string
175
     */
176
    private function addServices()
177
    {
178
        if (!$this->container->getDefinitions()) {
179
            return '';
180
        }
181
182
        $code = "services:\n";
183
        foreach ($this->container->getDefinitions() as $id => $definition) {
184
            $code .= $this->addService($id, $definition);
185
        }
186
187
        $aliases = $this->container->getAliases();
188 View Code Duplication
        foreach ($aliases as $alias => $id) {
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...
189
            while (isset($aliases[(string) $id])) {
190
                $id = $aliases[(string) $id];
191
            }
192
            $code .= $this->addServiceAlias($alias, $id);
193
        }
194
195
        return $code;
196
    }
197
198
    /**
199
     * Adds parameters.
200
     *
201
     * @return string
202
     */
203
    private function addParameters()
204
    {
205
        if (!$this->container->getParameterBag()->all()) {
206
            return '';
207
        }
208
209
        $parameters = $this->prepareParameters($this->container->getParameterBag()->all(), $this->container->isFrozen());
210
211
        return $this->dumper->dump(array('parameters' => $parameters), 2);
212
    }
213
214
    /**
215
     * Dumps callable to YAML format
216
     *
217
     * @param callable $callable
218
     *
219
     * @return callable
220
     */
221
    private function dumpCallable($callable)
222
    {
223
        if (is_array($callable)) {
224
            if ($callable[0] instanceof Reference) {
225
                $callable = array($this->getServiceCall((string) $callable[0], $callable[0]), $callable[1]);
226
            } else {
227
                $callable = array($callable[0], $callable[1]);
228
            }
229
        }
230
231
        return $callable;
232
    }
233
234
    /**
235
     * Dumps the value to YAML format.
236
     *
237
     * @param mixed $value
238
     *
239
     * @return mixed
240
     *
241
     * @throws RuntimeException When trying to dump object or resource
242
     */
243
    private function dumpValue($value)
244
    {
245
        if (is_array($value)) {
246
            $code = array();
247
            foreach ($value as $k => $v) {
248
                $code[$k] = $this->dumpValue($v);
249
            }
250
251
            return $code;
252
        } elseif ($value instanceof Reference) {
253
            return $this->getServiceCall((string) $value, $value);
254
        } elseif ($value instanceof Parameter) {
255
            return $this->getParameterCall((string) $value);
256
        } elseif ($value instanceof Expression) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\ExpressionLanguage\Expression does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
257
            return $this->getExpressionCall((string) $value);
258
        } elseif (is_object($value) || is_resource($value)) {
259
            throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
260
        }
261
262
        return $value;
263
    }
264
265
    /**
266
     * Gets the service call.
267
     *
268
     * @param string    $id
269
     * @param Reference $reference
270
     *
271
     * @return string
272
     */
273 View Code Duplication
    private function getServiceCall($id, Reference $reference = null)
274
    {
275
        if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
276
            return sprintf('@?%s', $id);
277
        }
278
279
        return sprintf('@%s', $id);
280
    }
281
282
    /**
283
     * Gets parameter call.
284
     *
285
     * @param string $id
286
     *
287
     * @return string
288
     */
289
    private function getParameterCall($id)
290
    {
291
        return sprintf('%%%s%%', $id);
292
    }
293
294
    private function getExpressionCall($expression)
295
    {
296
        return sprintf('@=%s', $expression);
297
    }
298
299
    /**
300
     * Prepares parameters.
301
     *
302
     * @param array $parameters
303
     * @param bool  $escape
304
     *
305
     * @return array
306
     */
307
    private function prepareParameters($parameters, $escape = true)
308
    {
309
        $filtered = array();
310
        foreach ($parameters as $key => $value) {
311
            if (is_array($value)) {
312
                $value = $this->prepareParameters($value, $escape);
313
            } elseif ($value instanceof Reference || is_string($value) && 0 === strpos($value, '@')) {
314
                $value = '@'.$value;
315
            }
316
317
            $filtered[$key] = $value;
318
        }
319
320
        return $escape ? $this->escape($filtered) : $filtered;
321
    }
322
323
    /**
324
     * Escapes arguments.
325
     *
326
     * @param array $arguments
327
     *
328
     * @return array
329
     */
330 View Code Duplication
    private function escape($arguments)
331
    {
332
        $args = array();
333
        foreach ($arguments as $k => $v) {
334
            if (is_array($v)) {
335
                $args[$k] = $this->escape($v);
336
            } elseif (is_string($v)) {
337
                $args[$k] = str_replace('%', '%%', $v);
338
            } else {
339
                $args[$k] = $v;
340
            }
341
        }
342
343
        return $args;
344
    }
345
}
346