PhpArrayDumper::getServiceDefinition()   F
last analyzed

Complexity

Conditions 16
Paths 8192

Size

Total Lines 64
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 16
eloc 34
c 1
b 0
f 0
nc 8192
nop 1
dl 0
loc 64
rs 2.8197

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
 * @file
4
 * Contains \Drupal\Core\DependencyInjection\Dumper\PhpArrayDumper
5
 */
6
7
namespace Drupal\Core\DependencyInjection\Dumper;
8
9
use Symfony\Component\DependencyInjection\Alias;
10
use Symfony\Component\DependencyInjection\ContainerInterface;
11
use Symfony\Component\DependencyInjection\Definition;
12
use Symfony\Component\DependencyInjection\Parameter;
13
use Symfony\Component\DependencyInjection\Reference;
14
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
15
use Symfony\Component\DependencyInjection\Dumper\Dumper;
16
17
/**
18
 * PhpArrayDumper dumps a service container as a serialized PHP array.
19
 */
20
class PhpArrayDumper extends Dumper
21
{
22
  /**
23
   * {@inheritdoc}
24
   */
25
  public function dump(array $options = array())
26
  {
27
    return serialize($this->getArray());
28
  }
29
30
  /**
31
   * Returns the service container as a PHP array.
32
   *
33
   * @return array
34
   *  A PHP array represention of the service container
35
   */
36
  public function getArray()
37
  {
38
    $definition = array();
39
    $definition['parameters'] = $this->getParameters();
40
    $definition['services'] = $this->getServiceDefinitions();
41
    return $definition;
42
  }
43
44
45
  /**
46
   * Returns parameters of the container as a PHP Array.
47
   *
48
   * @return array
49
   *   The escaped and prepared parameters of the container.
50
   */
51 View Code Duplication
  protected function getParameters()
52
  {
53
    if (!$this->container->getParameterBag()->all()) {
54
      return array();
55
    }
56
57
    $parameters = $this->container->getParameterBag()->all();
58
    $is_frozen = $this->container->isFrozen();
59
    return $this->prepareParameters($parameters, $is_frozen);
60
  }
61
62
  /**
63
   * Returns services of the container as a PHP Array.
64
   *
65
   * @return array
66
   *   The service definitions.
67
   */
68
  protected function getServiceDefinitions()
69
  {
70
    if (!$this->container->getDefinitions()) {
71
      return array();
72
    }
73
74
    $services = array();
75
    foreach ($this->container->getDefinitions() as $id => $definition) {
76
      $services[$id] = $this->getServiceDefinition($definition);
77
    }
78
79
    $aliases = $this->container->getAliases();
80 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...
81
      while (isset($aliases[(string) $id])) {
82
        $id = $aliases[(string) $id];
83
      }
84
      $services[$alias] = $this->getServiceAliasDefinition($id);
85
    }
86
87
    return $services;
88
  }
89
90
  /**
91
   * Prepares parameters.
92
   *
93
   * @param array $parameters
94
   * @param bool  $escape
95
   *
96
   * @return array
97
   */
98 View Code Duplication
  protected function prepareParameters($parameters, $escape = true)
99
  {
100
    $filtered = array();
101
    foreach ($parameters as $key => $value) {
102
      if (is_array($value)) {
103
        $value = $this->prepareParameters($value, $escape);
104
      }
105
      elseif ($value instanceof Reference) {
106
        $value = '@'.$value;
107
      }
108
109
      $filtered[$key] = $value;
110
    }
111
112
    return $escape ? $this->escape($filtered) : $filtered;
113
  }
114
115
  /**
116
   * Escapes arguments.
117
   *
118
   * @param array $arguments
119
   *   The arguments to escape.
120
   *
121
   * @return array
122
   *   The escaped arguments.
123
   */
124 View Code Duplication
  protected function escape($arguments)
125
  {
126
    $args = array();
127
    foreach ($arguments as $k => $v) {
128
      if (is_array($v)) {
129
        $args[$k] = $this->escape($v);
130
      }
131
      elseif (is_string($v)) {
132
        $args[$k] = str_replace('%', '%%', $v);
133
      }
134
      else {
135
        $args[$k] = $v;
136
      }
137
    }
138
139
    return $args;
140
  }
141
142
  /**
143
   * Gets a service definition as PHP array.
144
   *
145
   * @param \Symfony\Component\DependencyInjection\Definition $definition
146
   *   The definition to process.
147
   *
148
   * @return array
149
   *   The service definition as PHP array.
150
   */
151
  protected function getServiceDefinition($definition)
152
  {
153
    $service = array();
154
    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...
155
      $service['class'] = $definition->getClass();
156
    }
157
158
    if (!$definition->isPublic()) {
159
      $service['public'] = FALSE;
160
    }
161
162
    $tags = $definition->getTags();
163
    if (!empty($tags)) {
164
      foreach ($tags as $tag => $attributes) {
165
        $tag = ['name' => $tag];
166
        foreach ($attributes as $attribute) {
167
          $tag += $attribute;
168
        }
169
        $service['tags'][] = $tag;
170
      }
171
    }
172
173
    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...
174
      $service['file'] = $definition->getFile();
175
    }
176
177
    if ($definition->isSynthetic()) {
178
      $service['synthetic'] = TRUE;
179
    }
180
181
    if ($definition->isLazy()) {
182
      $service['lazy'] = TRUE;
183
    }
184
185
    if ($definition->getArguments()) {
186
      $service['arguments'] = $this->dumpValue($definition->getArguments());
187
    }
188
189
    if ($definition->getProperties()) {
190
      $service['properties'] = $this->dumpValue($definition->getProperties());
191
    }
192
193
    if ($definition->getMethodCalls()) {
194
      $service['calls'] = $this->dumpValue($definition->getMethodCalls());
195
    }
196
197
    if (($scope = $definition->getScope()) !== ContainerInterface::SCOPE_CONTAINER) {
198
      $service['scope'] = $scope;
199
    }
200
201
    if (($decorated = $definition->getDecoratedService()) !== NULL) {
202
      $service['decorates'] = $decorated;
203
    }
204
205
    if ($callable = $definition->getFactory()) {
206
      $service['factory'] = $this->dumpCallable($callable);
207
    }
208
209
    if ($callable = $definition->getConfigurator()) {
210
      $service['configurator'] = $this->dumpCallable($callable);
211
    }
212
213
    return $service;
214
  }
215
216
  /**
217
   * Returns a service alias definiton.
218
   *
219
   * @param string $alias
0 ignored issues
show
Bug introduced by
There is no parameter named $alias. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
220
   * @param Alias  $id
221
   *
222
   * @return string
223
   */
224
  protected function getServiceAliasDefinition($id)
225
  {
226
    if ($id->isPublic()) {
227
      return array(
228
        'alias' => (string) $id,
229
      );
230
    } else {
231
      return array(
232
        'alias' => (string) $id,
233
        'public' => FALSE,
234
      );
235
    }
236
  }
237
  /**
238
   * Dumps callable to YAML format
239
   *
240
   * @param callable $callable
241
   *
242
   * @return callable
243
   */
244
  protected function dumpCallable($callable)
245
  {
246
    if (is_array($callable)) {
247
      if ($callable[0] instanceof Reference) {
248
        $callable = array($this->getServiceCall((string) $callable[0], $callable[0]), $callable[1]);
249
      }
250
      elseif ($callable[0] instanceof Definition) {
251
        $callable[0] = $this->getPrivateService($callable[0]);
252
        $callable = array($callable[0], $callable[1]);
253
      }
254
      else {
255
        $callable = array($callable[0], $callable[1]);
256
      }
257
    }
258
259
    return $callable;
260
  }
261
262
  /**
263
   * Returns a private service definition in a suitable format.
264
   *
265
   * @param \Symfony\Component\DependencyInjection\Definition $definition
266
   *   The definition to process.
267
   *
268
   * @return \stdClass
269
   *   A very lightweight private service value object.
270
   */
271
  protected function getPrivateService(Definition $definition) {
272
    $service_definition = $this->getServiceDefinition($definition);
273
    $hash = sha1(serialize($service_definition));
274
    return (object) array(
275
      'type' => 'service',
276
      'id' => 'private__' . $hash,
277
      'value' => $service_definition,
278
    );
279
  }
280
281
  /**
282
   * Dumps the value to YAML format.
283
   *
284
   * @param mixed $value
285
   *
286
   * @return mixed
287
   *
288
   * @throws RuntimeException When trying to dump object or resource
289
   */
290
  protected function dumpValue($value)
291
  {
292
    if (is_array($value)) {
293
      $code = array();
294
      foreach ($value as $k => $v) {
295
        $code[$k] = $this->dumpValue($v);
296
      }
297
298
      return $code;
299
    } elseif ($value instanceof Reference) {
300
      return $this->getServiceCall((string) $value, $value);
301
    } elseif ($value instanceof Definition) {
302
      return $this->getPrivateService($value);
303
    } elseif ($value instanceof Parameter) {
304
      return $this->getParameterCall((string) $value);
305
    } elseif ($value instanceof Expression) {
0 ignored issues
show
Bug introduced by
The class Drupal\Core\DependencyInjection\Dumper\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...
306
      return $this->getExpressionCall((string) $value);
307 View Code Duplication
    } elseif (is_object($value)) {
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...
308
      if (isset($value->_serviceId)) {
309
        return '@' . $value->_serviceId;
310
      }
311
      throw new RuntimeException('Unable to dump a service container if a parameter is an object without _serviceId.');
312
    } elseif (is_resource($value)) {
313
      throw new RuntimeException('Unable to dump a service container if a parameter is a resource.');
314
    }
315
316
    return $value;
317
  }
318
319
  /**
320
   * Gets the service call.
321
   *
322
   * @param string  $id
323
   * @param Reference $reference
324
   *
325
   * @return string
326
   */
327 View Code Duplication
  protected function getServiceCall($id, Reference $reference = null)
328
  {
329
    if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
330
      return sprintf('@?%s', $id);
331
    }
332
333
    return sprintf('@%s', $id);
334
  }
335
336
  /**
337
   * Gets parameter call.
338
   *
339
   * @param string $id
340
   *
341
   * @return string
342
   */
343
  protected function getParameterCall($id)
344
  {
345
    return sprintf('%%%s%%', $id);
346
  }
347
348
  protected function getExpressionCall($expression)
349
  {
350
    return sprintf('@=%s', $expression);
351
  }
352
}
353