Completed
Push — master ( 07cf6c...fa3c04 )
by Vitaly
02:59
created

ContainerBuilder   C

Complexity

Total Complexity 72

Size/Duplication

Total Lines 607
Duplicated Lines 3.62 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 94.59%

Importance

Changes 0
Metric Value
wmc 72
lcom 1
cbo 6
dl 22
loc 607
ccs 210
cts 222
cp 0.9459
rs 5.5312
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A loadFromPaths() 0 11 2
A loadFromClassNames() 0 16 3
C getDefinedClasses() 0 28 13
A loadFromCode() 0 10 2
B build() 0 51 5
A buildDependencyResolver() 0 14 1
C generateConditions() 0 87 12
A buildResolverCondition() 0 11 3
A getValidClassMethodsMetadata() 0 13 4
A getValidClassPropertiesMetadata() 0 13 3
A buildResolvingClassDeclaration() 0 4 1
B buildConstructorDependencies() 0 29 5
B buildResolverArgument() 0 15 5
B buildReflectionClass() 22 39 6
B buildResolverPropertyDeclaration() 0 32 2
B buildResolverMethodDeclaration() 0 38 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ContainerBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ContainerBuilder, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types = 1);
2
/**
3
 * Created by PhpStorm.
4
 * User: root
5
 * Date: 02.08.16
6
 * Time: 0:46.
7
 */
8
namespace samsonframework\container;
9
10
use samsonframework\container\metadata\ClassMetadata;
11
use samsonframework\container\metadata\MethodMetadata;
12
use samsonframework\container\metadata\PropertyMetadata;
13
use samsonframework\container\resolver\ResolverInterface;
14
use samsonframework\di\Container;
15
use samsonframework\filemanager\FileManagerInterface;
16
use samsonphp\generator\Generator;
17
18
/**
19
 * Class Container.
20
 */
21
class ContainerBuilder
22
{
23
    /** Controller classes scope name */
24
    const SCOPE_CONTROLLER = 'controllers';
25
26
    /** Service classes scope name */
27
    const SCOPE_SERVICES = 'services';
28
29
    /** Generated resolving function name prefix */
30
    const DI_FUNCTION_PREFIX = 'container';
31
32
    /** Generated resolving function service static collection name */
33
    const DI_FUNCTION_SERVICES = '$' . self::SCOPE_SERVICES;
34
35
    /** @var string[] Collection of available container scopes */
36
    protected $scopes = [
37
        self::SCOPE_CONTROLLER => [],
38
        self::SCOPE_SERVICES => []
39
    ];
40
41
    /** @var ClassMetadata[] Collection of classes metadata */
42
    protected $classMetadata = [];
43
44
    /** @var array Collection of dependencies aliases */
45
    protected $classAliases = [];
46
47
    /**
48
     * @var FileManagerInterface
49
     * @Injectable
50
     */
51
    protected $fileManger;
52
53
    /**
54
     * @var ResolverInterface
55
     * @Injectable
56
     */
57
    protected $classResolver;
58
59
    /**
60
     * @var Generator
61
     * @Injectable
62
     */
63
    protected $generator;
64
65
    /** @var string Resolver function name */
66
    protected $resolverFunction;
67
68
    /**
69
     * Container constructor.
70
     *
71
     * @param FileManagerInterface $fileManager
72
     * @param ResolverInterface    $classResolver
73
     * @param Generator            $generator
74
     */
75 10
    public function __construct(
76
        FileManagerInterface $fileManager,
77
        ResolverInterface $classResolver,
78
        Generator $generator
79
    )
80
    {
0 ignored issues
show
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
81 10
        $this->fileManger = $fileManager;
82 10
        $this->classResolver = $classResolver;
83 10
        $this->generator = $generator;
84 10
    }
85
86
    /**
87
     * Load classes from paths.
88
     *
89
     * @param array $paths Paths for importing
90
     *
91
     * @return $this
92
     */
93 1
    public function loadFromPaths(array $paths)
94
    {
95
        // Iterate all paths and get files
96 1
        foreach ($this->fileManger->scan($paths, ['php']) as $phpFile) {
97 1
            require_once($phpFile);
98
            // Read all classes in given file
99 1
            $this->loadFromClassNames($this->getDefinedClasses(file_get_contents($phpFile)));
100
        }
101
102 1
        return $this;
103
    }
104
105
    /**
106
     * Load classes from class names collection.
107
     *
108
     * @param string[] $classes Collection of class names for resolving
109
     *
110
     * @return $this
111
     */
112 10
    public function loadFromClassNames(array $classes)
113
    {
114
        // Read all classes in given file
115 10
        foreach ($classes as $className) {
116
            // Resolve class metadata
117 10
            $this->classMetadata[$className] = $this->classResolver->resolve(new \ReflectionClass($className));
118
            // Store by metadata name as alias
119 10
            $this->classAliases[$this->classMetadata[$className]->name] = $className;
120
            // Store class in defined scopes
121 10
            foreach ($this->classMetadata[$className]->scopes as $scope) {
122 10
                $this->scopes[$scope][] = $className;
123
            }
124
        }
125
126 10
        return $this;
127
    }
128
129
    /**
130
     * Find class names defined in PHP code.
131
     *
132
     * @param string $php PHP code for scanning
133
     *
134
     * @return string[] Collection of found class names in php code
135
     */
136 2
    protected function getDefinedClasses(string $php) : array
137
    {
138 2
        $classes = [];
139 2
        $namespace = null;
140
141
        // Append php marker for parsing file
142 2
        $php = strpos(is_string($php) ? $php : '', '<?php') !== 0 ? '<?php ' . $php : $php;
143
144 2
        $tokens = token_get_all($php);
145
146 2
        for ($i = 2, $count = count($tokens); $i < $count; $i++) {
147 2
            if ($tokens[$i - 2][0] === T_CLASS
148 2
                && $tokens[$i - 1][0] === T_WHITESPACE
149 2
                && $tokens[$i][0] === T_STRING
150
            ) {
151 2
                $classes[] = $namespace ? $namespace . '\\' . $tokens[$i][1] : $tokens[$i][1];
152 2
            } elseif ($tokens[$i - 2][0] === T_NAMESPACE
153 2
                && $tokens[$i - 1][0] === T_WHITESPACE
154 2
                && $tokens[$i][0] === T_STRING
155
            ) {
156 1
                while (isset($tokens[$i]) && is_array($tokens[$i])) {
157 1
                    $namespace .= $tokens[$i++][1];
158
                }
159
            }
160
        }
161
162 2
        return $classes;
163
    }
164
165
    /**
166
     * Load classes from PHP c ode.
167
     *
168
     * @param string $php PHP code
169
     *
170
     * @return $this
171
     */
172 1
    public function loadFromCode($php)
173
    {
174 1
        if (count($classes = $this->getDefinedClasses($php))) {
175
            // TODO: Consider writing cache file and require it
176 1
            eval($php);
177 1
            $this->loadFromClassNames($classes);
178
        }
179
180 1
        return $this;
181
    }
182
183
    /**
184
     * Build container class.
185
     *
186
     * @param string|null $containerClass Container class name
187
     * @param string      $namespace      Name space
188
     *
189
     * @return string Generated Container class code
190
     * @throws \InvalidArgumentException
191
     */
192 7
    public function build($containerClass = 'Container', $namespace = '')
193
    {
194
        // Build dependency injection container function name
195 7
        $this->resolverFunction = uniqid(self::DI_FUNCTION_PREFIX);
196
197 7
        $containerDependencies = [];
198 7
        $containerAliases = [];
199 7
        foreach ($this->classMetadata as $className => $classMetadata) {
200 7
            if ($classMetadata->alias !== null) {
201
                $containerAliases[$className] = $classMetadata->alias;
202
            }
203
            // Store inner dependencies
204 7
            if (array_key_exists('__construct', $classMetadata->methodsMetadata)) {
205 7
                $containerDependencies[$className] = array_values($classMetadata->methodsMetadata['__construct']->dependencies);
206
            }
207
        }
208
209 7
        $this->generator
210 7
            ->text('<?php declare(strict_types = 1);')
211 7
            ->newLine()
212 7
            ->defNamespace($namespace)
213 7
            ->multiComment(['Application container'])
214 7
            ->defClass($containerClass, '\\' . Container::class)
215 7
            ->defClassFunction('__construct')
216 7
            ->newLine('$this->dependencies = ')->arrayValue($containerDependencies)->text(';')
217 7
            ->newLine('$this->aliases = ')->arrayValue($containerAliases)->text(';')
218 7
            ->newLine('$this->' . self::SCOPE_SERVICES . ' = ')->arrayValue($this->scopes[self::SCOPE_SERVICES])->text(';')
0 ignored issues
show
Documentation introduced by
$this->scopes[self::SCOPE_SERVICES] is of type string, but the function expects a array.

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...
219 7
            ->endClassFunction()
220 7
            ->defClassFunction('logic', 'protected', ['$dependency'], ['{@inheritdoc}'])
221 7
            ->newLine('return $this->' . $this->resolverFunction . '($dependency);')
222 7
            ->endClassFunction();
223
224 7
        foreach ($this->classMetadata as $className => $classMetadata) {
225 7
            $dependencyName = $classMetadata->name ?? $className;
226
227
            // Generate camel case getter method
228 7
            $camelMethodName = 'get' . str_replace(' ', '', ucwords(ucfirst(str_replace(['\\', '_'], ' ', $dependencyName))));
229
230 7
            $this->generator
231 7
                ->defClassFunction($camelMethodName, 'public', [], ['@return \\' . $className . ' Get ' . $dependencyName . ' instance'])
232 7
                ->newLine('return $this->' . $this->resolverFunction . '(\'' . $dependencyName . '\');')
233 7
                ->endClassFunction();
234
        }
235
236
        // Build di container function and add to container class and return class code
237 7
        $this->buildDependencyResolver($this->resolverFunction);
238
239 7
        return $this->generator
240 7
            ->endClass()
241 7
            ->flush();
242
    }
243
244
    /**
245
     * Build dependency resolving function.
246
     *
247
     * @param string $functionName Function name
248
     *
249
     * @throws \InvalidArgumentException
250
     */
251 7
    protected function buildDependencyResolver($functionName)
252
    {
253 7
        $inputVariable = '$aliasOrClassName';
254 7
        $this->generator
255 7
            ->defClassFunction($functionName, 'protected', [$inputVariable], ['Dependency resolving function'])
256 7
            ->defVar('static ' . self::DI_FUNCTION_SERVICES . ' = []')
257 7
            ->newLine();
258
259
        // Generate all container and delegate conditions
260 7
        $this->generateConditions($inputVariable, false);
261
262
        // Add method not found
263 7
        $this->generator->endIfCondition()->endFunction();
264 7
    }
265
266
    /**
267
     * Generate logic conditions and their implementation for container and its delegates.
268
     *
269
     * @param string     $inputVariable Input condition parameter variable name
270
     * @param bool|false $started       Flag if condition branching has been started
271
     */
272 7
    public function generateConditions($inputVariable = '$alias', $started = false)
273
    {
274
        // Iterate all container dependencies
275 7
        foreach ($this->classMetadata as $className => $classMetadata) {
276
            // Generate condition statement to define if this class is needed
277 7
            $conditionFunc = !$started ? 'defIfCondition' : 'defElseIfCondition';
278
279
            // Output condition branch
280 7
            $this->generator->$conditionFunc(
281 7
                $this->buildResolverCondition($inputVariable, $className, $classMetadata->name)
282
            );
283
284
            // Define if this class has service scope
285 7
            $isService = in_array($className, $this->scopes[self::SCOPE_SERVICES], true);
286
287
            /** @var MethodMetadata[] Gather only valid method for container */
288 7
            $classValidMethods = $this->getValidClassMethodsMetadata($classMetadata->methodsMetadata);
289
290
            /** @var PropertyMetadata[] Gather only valid property for container */
291 7
            $classValidProperties = $this->getValidClassPropertiesMetadata($classMetadata->propertiesMetadata);
292
293
            // Define class or service variable
294 7
            $staticContainerName = $isService
295 7
                ? self::DI_FUNCTION_SERVICES . '[\'' . $classMetadata->name . '\']'
296 7
                : '$temp';
297
298 7
            if ($isService) {
299
                // Check if dependency was instantiated
300 7
                $this->generator->defIfCondition('!array_key_exists(\'' . $className . '\', ' . self::DI_FUNCTION_SERVICES . ')');
301
            }
302
303 7
            if (count($classValidMethods) || count($classValidProperties)) {
304 7
                $this->generator->newLine($staticContainerName . ' = ');
305 7
                $this->buildResolvingClassDeclaration($className);
306 7
                $this->buildConstructorDependencies($classMetadata->methodsMetadata);
307
308
                // Internal scope reflection variable
309 7
                $reflectionVariable = '$reflectionClass';
310
311 7
                $this->buildReflectionClass($className, $classValidProperties, $classValidMethods, $reflectionVariable);
312
313
                // Process class properties
314 7
                foreach ($classValidProperties as $property) {
315
                    // If such property has the dependency
316 7
                    if ($property->dependency) {
317
                        // Set value via refection
318 7
                        $this->buildResolverPropertyDeclaration(
319 7
                            $property->name,
320 7
                            $property->dependency,
321
                            $staticContainerName,
322
                            $reflectionVariable,
323 7
                            $property->isPublic
324
                        );
325
                    }
326
                }
327
328
                /** @var MethodMetadata $methodMetadata */
329 7
                foreach ($classValidMethods as $methodName => $methodMetadata) {
330 7
                    $this->buildResolverMethodDeclaration(
331 7
                        $methodMetadata->dependencies,
332
                        $methodName,
333
                        $staticContainerName,
334
                        $reflectionVariable,
335 7
                        $methodMetadata->isPublic
336
                    );
337
                }
338
339 7
                if ($isService) {
340 7
                    $this->generator->endIfCondition();
341
                }
342
343 7
                $this->generator->newLine()->newLine('return ' . $staticContainerName . ';');
344
            } else {
345 7
                $this->generator->newLine('return ');
346 7
                $this->buildResolvingClassDeclaration($className);
347 7
                $this->buildConstructorDependencies($classMetadata->methodsMetadata);
348
349 7
                if ($isService) {
350
                    $this->generator->endIfCondition()->newLine('return ' . $staticContainerName . ';');
351
                }
352
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
353
            }
354
355
            // Set flag that condition is started
356 7
            $started = true;
357
        }
358 7
    }
359
360
    /**
361
     * Build resolving function condition.
362
     *
363
     * @param string      $inputVariable Condition variable
364
     * @param string      $className
365
     * @param string|null $alias
366
     *
367
     * @return string Condition code
368
     */
369 7
    protected function buildResolverCondition(string $inputVariable, string $className, string $alias = null) : string
370
    {
371
        // Create condition branch
372 7
        $condition = $inputVariable . ' === \'' . $className . '\'';
373
374 7
        if ($alias !== null && $alias !== $className) {
375 7
            $condition .= '||' . $this->buildResolverCondition($inputVariable, $alias);
376
        }
377
378 7
        return $condition;
379
    }
380
381
    /**
382
     * Get valid class methods metadata.
383
     *
384
     * @param MethodMetadata[] $classMethodsMetadata All class methods metadata
385
     *
386
     * @return array Valid class methods metadata
387
     */
388 7
    protected function getValidClassMethodsMetadata(array $classMethodsMetadata)
389
    {
390
        /** @var MethodMetadata[] Gather only valid method for container */
391 7
        $classValidMethods = [];
392 7
        foreach ($classMethodsMetadata as $methodName => $methodMetadata) {
393
            // Skip constructor method and empty dependencies
394 7
            if ($methodName !== '__construct' && count($methodMetadata->dependencies) > 0) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of $methodName (integer) and '__construct' (string) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
395 7
                $classValidMethods[$methodName] = $methodMetadata;
396
            }
397
        }
398
399 7
        return $classValidMethods;
400
    }
401
402
    /**
403
     * Get valid class properties metadata.
404
     *
405
     * @param PropertyMetadata[] $classPropertiesMetadata All class properties metadata
406
     *
407
     * @return array Valid class properties metadata
408
     */
409 7
    protected function getValidClassPropertiesMetadata(array $classPropertiesMetadata)
410
    {
411
        /** @var PropertyMetadata[] Gather only valid property for container */
412 7
        $classValidProperties = [];
413 7
        foreach ($classPropertiesMetadata as $propertyName => $propertyMetadata) {
414
            // Skip constructor method and empty dependencies
415 7
            if ($propertyMetadata->dependency) {
416 7
                $classValidProperties[$propertyName] = $propertyMetadata;
417
            }
418
        }
419
420 7
        return $classValidProperties;
421
    }
422
423
    /**
424
     * Build resolving function class block.
425
     *
426
     * @param string $className Class name for new instance creation
427
     */
428 7
    protected function buildResolvingClassDeclaration(string $className)
429
    {
430 7
        $this->generator->text('new \\' . ltrim($className, '\\') . '(');
431 7
    }
432
433
    /**
434
     * Build constructor arguments injection.
435
     *
436
     * @param MethodMetadata[] $methodsMetaData
437
     */
438 7
    protected function buildConstructorDependencies(array $methodsMetaData)
439
    {
440
        // Process constructor dependencies
441 7
        $argumentsCount = 0;
442 7
        if (array_key_exists('__construct', $methodsMetaData)) {
443 7
            $constructorArguments = $methodsMetaData['__construct']->dependencies;
444 7
            $argumentsCount = count($constructorArguments);
445 7
            $i = 0;
446
447
            // Add indentation to move declaration arguments
448 7
            $this->generator->tabs++;
449
450
            // Process constructor arguments
451 7
            foreach ($constructorArguments as $argument => $dependency) {
452 7
                $this->buildResolverArgument($dependency);
453
454
                // Add comma if this is not last dependency
455 7
                if (++$i < $argumentsCount) {
456 7
                    $this->generator->text(',');
457
                }
458
            }
459
460
            // Restore indentation
461 7
            $this->generator->tabs--;
462
        }
463
464
        // Close declaration block, multiline if we have dependencies
465 7
        $argumentsCount ? $this->generator->newLine(');') : $this->generator->text(');');
466 7
    }
467
468
    /**
469
     * Build resolving function dependency argument.
470
     *
471
     * @param mixed $argument Dependency argument
472
     */
473 7
    protected function buildResolverArgument($argument, $textFunction = 'newLine')
474
    {
475
        // This is a dependency which invokes resolving function
476 7
        if (array_key_exists($argument, $this->classMetadata)) {
477
            // Call container logic for this dependency
478 7
            $this->generator->$textFunction('$this->' . $this->resolverFunction . '(\'' . $argument . '\')');
479
        } elseif (array_key_exists($argument, $this->classAliases)) {
480
            // Call container logic for this dependency
481
            $this->generator->$textFunction('$this->' . $this->resolverFunction . '(\'' . $argument . '\')');
482
        } elseif (is_string($argument)) { // String variable
483
            $this->generator->$textFunction()->stringValue($argument);
484
        } elseif (is_array($argument)) { // Dependency value is array
485
            $this->generator->$textFunction()->arrayValue($argument);
486
        }
487 7
    }
488
489
    /**
490
     * Generate reflection class for private/protected methods or properties
491
     * in current scope.
492
     *
493
     * @param string             $className          Reflection class source class name
494
     * @param PropertyMetadata[] $propertiesMetadata Properties metadata
495
     * @param MethodMetadata[]   $methodsMetadata    Methods metadata
496
     * @param string             $reflectionVariable Reflection class variable name
497
     */
498 7
    protected function buildReflectionClass(string $className, array $propertiesMetadata, array $methodsMetadata, string $reflectionVariable)
499
    {
500
        /** @var bool $reflectionClassCreated Flag showing that reflection class already created in current scope */
501 7
        $reflectionClassCreated = false;
502
503
        /**
504
         * Iterate all properties and create internal scope reflection class instance if
505
         * at least one property in not public
506
         */
507 7 View Code Duplication
        foreach ($propertiesMetadata as $propertyMetadata) {
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...
508 7
            if (!$propertyMetadata->isPublic) {
509 7
                $this->generator
510 7
                    ->comment('Create reflection class for injecting private/protected properties and methods')
511 7
                    ->newLine($reflectionVariable . ' = new \ReflectionClass(\'' . $className . '\');')
512 7
                    ->newLine();
513
514 7
                $reflectionClassCreated = true;
515
516 7
                break;
517
            }
518
        }
519
520
        /**
521
         * Iterate all properties and create internal scope reflection class instance if
522
         * at least one property in not public
523
         */
524 7
        if (!$reflectionClassCreated) {
525 7 View Code Duplication
            foreach ($methodsMetadata as $methodMetadata) {
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...
526 7
                if (!$methodMetadata->isPublic) {
527
                    $this->generator
528
                        ->comment('Create reflection class for injecting private/protected properties and methods')
529
                        ->newLine($reflectionVariable . ' = new \ReflectionClass(\'' . $className . '\');')
530
                        ->newLine();
531
532 7
                    break;
533
                }
534
            }
535
        }
536 7
    }
537
538
    /**
539
     * Build resolving property injection declaration.
540
     *
541
     * @param string $propertyName       Target property name
542
     * @param string $dependency         Dependency class name
543
     * @param string $containerVariable  Container declaration variable name
544
     * @param string $reflectionVariable Reflection class variable name
545
     * @param bool   $isPublic           Flag if property is public
546
     */
547 7
    protected function buildResolverPropertyDeclaration(
548
        string $propertyName,
549
        string $dependency,
550
        string $containerVariable,
551
        string $reflectionVariable,
552
        bool $isPublic
553
    )
554
    {
0 ignored issues
show
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
555 7
        if ($isPublic) {
556 7
            $this->generator
557 7
                ->comment('Inject public dependency for $' . $propertyName)
558 7
                ->newLine($containerVariable . '->' . $propertyName . ' = ');
559 7
            $this->buildResolverArgument($dependency, 'text');
560 7
            $this->generator->text(';');
561
        } else {
562 7
            $this->generator
563 7
                ->comment('Inject private dependency for $' . $propertyName)
564 7
                ->newLine('$property = ' . $reflectionVariable . '->getProperty(\'' . $propertyName . '\');')
565 7
                ->newLine('$property->setAccessible(true);')
566 7
                ->newLine('$property->setValue(')
567 7
                ->increaseIndentation()
568 7
                ->newLine($containerVariable . ',');
569
570 7
            $this->buildResolverArgument($dependency);
571
572 7
            $this->generator
573 7
                ->decreaseIndentation()
574 7
                ->newLine(');')
575 7
                ->newLine('$property->setAccessible(false);')
576 7
                ->newLine();
577
        }
578 7
    }
579
580
    /**
581
     * Build resolving method injection declaration.
582
     *
583
     * @param array  $dependencies       Collection of method dependencies
584
     * @param string $methodName         Method name
585
     * @param string $containerVariable  Container declaration variable name
586
     * @param string $reflectionVariable Reflection class variable name
587
     * @param bool   $isPublic           Flag if method is public
588
     */
589 7
    protected function buildResolverMethodDeclaration(
590
        array $dependencies,
591
        string $methodName,
592
        string $containerVariable,
593
        string $reflectionVariable,
594
        bool $isPublic
595
    )
596
    {
0 ignored issues
show
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
597
        // Get method arguments
598 7
        $argumentsCount = count($dependencies);
599
600 7
        $this->generator->comment('Invoke ' . $methodName . '() and pass dependencies(y)');
601
602 7
        if ($isPublic) {
603 7
            $this->generator->newLine($containerVariable . '->' . $methodName . '(')->increaseIndentation();
604
        } else {
605 7
            $this->generator
606 7
                ->newLine('$method = ' . $reflectionVariable . '->getMethod(\'' . $methodName . '\');')
607 7
                ->newLine('$method->setAccessible(true);')
608 7
                ->newLine('$method->invoke(')
609 7
                ->increaseIndentation()
610 7
                ->newLine($containerVariable . ',');
611
        }
612
613 7
        $i = 0;
614
        // Iterate method arguments
615 7
        foreach ($dependencies as $argument => $dependency) {
616
            // Add dependencies
617 7
            $this->buildResolverArgument($dependency);
618
619
            // Add comma if this is not last dependency
620 7
            if (++$i < $argumentsCount) {
621 7
                $this->generator->text(',');
622
            }
623
        }
624
625 7
        $this->generator->decreaseIndentation()->newLine(');');
626 7
    }
627
}
628