Completed
Push — master ( 5bb4f6...c3b142 )
by
unknown
03:02
created

Builder::buildResolverArgument()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 0
cts 11
cp 0
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 5
nop 2
crap 30
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\ContainerInterface;
11
use samsonframework\container\metadata\ClassMetadata;
12
use samsonframework\container\metadata\MethodMetadata;
13
use samsonframework\container\metadata\PropertyMetadata;
14
use samsonframework\di\Container;
15
use samsonphp\generator\Generator;
16
17
/**
18
 * Container builder.
19
 *
20
 * @author Vitaly Egorov <[email protected]>
21
 */
22
class Builder implements ContainerBuilderInterface
23
{
24
    /** Controller classes scope name */
25
    const SCOPE_CONTROLLER = 'controllers';
26
27
    /** Service classes scope name */
28
    const SCOPE_SERVICES = 'service';
29
30
    /** Generated resolving function name prefix */
31
    const DI_FUNCTION_PREFIX = 'container';
32
33
    /** Generated resolving function service static collection name */
34
    const DI_FUNCTION_SERVICES = self::SCOPE_SERVICES . 'Instances';
35
36
    /** @var string[] Collection of available container scopes */
37
    protected $scopes = [
38
        self::SCOPE_CONTROLLER => [],
39
        self::SCOPE_SERVICES => []
40
    ];
41
42
    /** @var ClassMetadata[] Collection of classes metadata */
43
    protected $classesMetadata = [];
44
45
    /** @var array Collection of dependencies aliases */
46
    protected $classAliases = [];
47
48
    /** @var  ContainerInterface */
49
    protected $parentContainer;
50
51
    /**
52
     * @var Generator
53
     * @Injectable
54
     */
55
    protected $generator;
56
57
    /** @var string Resolver function name */
58
    protected $resolverFunction;
59
60
    /**
61
     * Container builder constructor.
62
     *
63
     * @param Generator       $generator     PHP code generator
64
     * @param ClassMetadata[] $classMetadata Collection of classes metadata for container
0 ignored issues
show
Bug introduced by
There is no parameter named $classMetadata. 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...
65
     */
66 2
    public function __construct(Generator $generator)
67
    {
68 2
        $this->generator = $generator;
69 2
    }
70
71
    /**
72
     * {@inheritdoc}
73
     */
74 2
    public function build(array $classesMetadata, $containerClass = 'Container', $namespace = '', ContainerInterface $parentContainer = null)
75
    {
76 2
        $this->classesMetadata = $this->processClassMetadata($classesMetadata);
77
        $this->parentContainer = $parentContainer;
78
79
        // Build dependency injection container function name
80
        $this->resolverFunction = uniqid(self::DI_FUNCTION_PREFIX);
81
82
        $containerDependencies = [];
83
        foreach ($classesMetadata as $classMetadata) {
84
            $className = $classMetadata->className;
85
            // Store inner dependencies
86
            if (array_key_exists('__construct', $classMetadata->methodsMetadata)) {
87
                $containerDependencies[$className] = array_values($classMetadata->methodsMetadata['__construct']->dependencies ?? []);
88
            }
89
        }
90
91
        $this->generator
92
            ->text('<?php declare(strict_types = 1);')
93
            ->newLine()
94
            ->defNamespace($namespace)
95
            ->multiComment(['Application container'])
96
            ->defClass($containerClass, '\\' . Container::class)
97
            ->multiComment(['@var array Collection of service instances'])
98
            ->defClassFunction('__construct', 'public', [], ['Container constructor'])
99
            ->newLine('$this->dependencies = ')->arrayValue($containerDependencies)->text(';')
100
            ->newLine('$this->aliases = ')->arrayValue($this->classAliases)->text(';')
101
            ->newLine('$this->scopes = ')->arrayValue($this->scopes)->text(';')
102
            ->newLine('$this->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...
103
            ->endClassFunction()
104
            ->defClassFunction('logic', 'protected', ['$dependency'], ['{@inheritdoc}'])
105
            ->newLine('return $this->' . $this->resolverFunction . '($dependency);')
106
            ->endClassFunction();
107
108
        foreach ($classesMetadata as $classMetadata) {
109
            $className = $classMetadata->className;
110
            $dependencyName = $classMetadata->name ?? $className;
111
112
            // Generate camel case getter method
113
            $camelMethodName = 'get' . str_replace(' ', '', ucwords(ucfirst(str_replace(['\\', '_'], ' ', $dependencyName))));
114
115
            $this->generator
116
                ->defClassFunction($camelMethodName, 'public', [], ['@return ' . '\\'.ltrim($className, '\\') . ' Get ' . $dependencyName . ' instance'])
117
                ->newLine('return $this->' . $this->resolverFunction . '(\'' . $dependencyName . '\');')
118
                ->endClassFunction();
119
        }
120
121
        // Build di container function and add to container class and return class code
122
        $this->buildDependencyResolver($this->resolverFunction);
123
124
        return $this->generator
125
            ->endClass()
126
            ->flush();
127
    }
128
129
    /**
130
     * Read class metadata and fill internal collections.
131
     *
132
     * @param ClassMetadata[] $classesMetadata
133
     * @return ClassMetadata[] Processed class metadata
134
     */
135 2
    public function processClassMetadata(array $classesMetadata) : array
136
    {
137
        /** @var ClassMetadata[] $processedClassesMetadata */
138 2
        $processedClassesMetadata = [];
139
140
        // Read all classes in given file
141 2
        foreach ($classesMetadata as $classMetadata) {
142
            // Store by metadata name as alias
143 2
            $this->classAliases[$classMetadata->className] = $classMetadata->name;
144
145
            // Store class in defined scopes
146 2
            foreach ($classMetadata->scopes as $scope) {
147 2
                $this->scopes[$scope][$classMetadata->name] = $classMetadata->className;
148
            }
149 2
            $processedClassesMetadata[$classMetadata->name] = $classMetadata;
150
        }
151
152 2
        $dependencies = [];
153 2
        foreach ($processedClassesMetadata as $alias => $classMetadata) {
154 2
            if (count($classMetadata->methodsMetadata)) {
155 2
                foreach ($classMetadata->methodsMetadata as $methodMetadata) {
156 2
                    foreach ($methodMetadata->dependencies as $dependency) {
157 2
                        if (in_array($this->getArgumentType($dependency), [1, 2], true)) {
158 2
                            $dependencies[] = $dependency;
159
                        }
160
                    }
161
                }
162
                $dependencies[] = $classMetadata->name;
163
            }
164
            if (count($classMetadata->propertiesMetadata)) {
165
                foreach ($classMetadata->propertiesMetadata as $propertyMetadata) {
166
                    $dependencies[] = $propertyMetadata->dependency;
167
                }
168
                $dependencies[] = $classMetadata->name;
169
            }
170
            if (count($classMetadata->scopes)) {
171
                $dependencies[] = $classMetadata->name;
172
            }
173
        }
174
        $dependencies = array_unique($dependencies);
175
176
        foreach ($processedClassesMetadata as $alias => $classMetadata) {
177
            if (!in_array($alias, $dependencies, true)) {
178
                unset($processedClassesMetadata[$alias]);
179
            }
180
        }
181
        $this->generator->flush();
182
183
        return $processedClassesMetadata;
184
    }
185
186
    /**
187
     * Build dependency resolving function.
188
     *
189
     * @param string $functionName Function name
190
     *
191
     * @throws \InvalidArgumentException
192
     */
193
    protected function buildDependencyResolver($functionName)
194
    {
195
        $inputVariable = '$aliasOrClassName';
196
        $this->generator
197
            ->defClassFunction($functionName, 'protected', [$inputVariable], ['Dependency resolving function'])
198
            //->defVar('static ' . self::DI_FUNCTION_SERVICES . ' = []')
199
            ->newLine();
200
201
        // Generate all container and delegate conditions
202
        $this->generateConditions($inputVariable, false);
203
204
        // Add method not found
205
        $this->generator->endIfCondition()->endFunction();
206
    }
207
208
    /**
209
     * Generate logic conditions and their implementation for container and its delegates.
210
     *
211
     * @param string     $inputVariable Input condition parameter variable name
212
     * @param bool|false $started       Flag if condition branching has been started
213
     */
214
    public function generateConditions($inputVariable = '$alias', $started = false)
215
    {
216
        // Iterate all container dependencies
217
        foreach ($this->classesMetadata as $classMetadata) {
218
            $className = $classMetadata->className;
219
            // Generate condition statement to define if this class is needed
220
            $conditionFunc = !$started ? 'defIfCondition' : 'defElseIfCondition';
221
222
            // Output condition branch
223
            $this->generator->$conditionFunc(
224
                $this->buildResolverCondition($inputVariable, $className, $classMetadata->name)
225
            );
226
227
            // Define if this class has service scope
228
            $isService = in_array($className, $this->scopes[self::SCOPE_SERVICES], true);
229
230
            /** @var MethodMetadata[] Gather only valid method for container */
231
            $classValidMethods = $this->getValidClassMethodsMetadata($classMetadata->methodsMetadata);
232
233
            /** @var PropertyMetadata[] Gather only valid property for container */
234
            $classValidProperties = $this->getValidClassPropertiesMetadata($classMetadata->propertiesMetadata);
235
236
            // Define class or service variable
237
            $staticContainerName = $isService
238
                ? '$this->' . self::DI_FUNCTION_SERVICES . '[\'' . $classMetadata->name . '\']'
239
                : '$temp';
240
241
            if ($isService) {
242
                // Check if dependency was instantiated
243
                $this->generator->defIfCondition('!array_key_exists(\'' . $classMetadata->name . '\', $this->' . self::DI_FUNCTION_SERVICES . ')');
244
            }
245
246
            if (count($classValidMethods) || count($classValidProperties)) {
247
                $this->generator->newLine($staticContainerName . ' = ');
248
                $this->buildResolvingClassDeclaration($className);
249
                $this->buildConstructorDependencies($classMetadata->methodsMetadata);
250
251
                // Internal scope reflection variable
252
                $reflectionVariable = '$reflectionClass';
253
254
                $this->buildReflectionClass($className, $classValidProperties, $classValidMethods, $reflectionVariable);
255
256
                // Process class properties
257
                foreach ($classValidProperties as $property) {
258
                    // If such property has the dependency
259
                    if ($property->dependency) {
260
                        // Set value via refection
261
                        $this->buildResolverPropertyDeclaration(
262
                            $property->name,
263
                            $property->dependency,
264
                            $staticContainerName,
265
                            $reflectionVariable,
266
                            $property->isPublic
267
                        );
268
                    }
269
                }
270
271
                /** @var MethodMetadata $methodMetadata */
272
                foreach ($classValidMethods as $methodName => $methodMetadata) {
273
                    $this->buildResolverMethodDeclaration(
274
                        $methodMetadata->dependencies,
275
                        $methodName,
276
                        $staticContainerName,
277
                        $reflectionVariable,
278
                        $methodMetadata->isPublic
279
                    );
280
                }
281
282
                if ($isService) {
283
                    $this->generator->endIfCondition();
284
                }
285
286
                $this->generator->newLine()->newLine('return ' . $staticContainerName . ';');
287
            } else {
288
                if ($isService) {
289
                    $this->generator->newLine($staticContainerName.' = ');
290
                    $this->buildResolvingClassDeclaration($className);
291
                    $this->buildConstructorDependencies($classMetadata->methodsMetadata);
292
                    $this->generator->endIfCondition()->newLine('return ' . $staticContainerName . ';');
293
                } else {
294
                    $this->generator->newLine('return ');
295
                    $this->buildResolvingClassDeclaration($className);
296
                    $this->buildConstructorDependencies($classMetadata->methodsMetadata);
297
                }
298
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
299
            }
300
301
            // Set flag that condition is started
302
            $started = true;
303
        }
304
    }
305
306
    /**
307
     * Build resolving function condition.
308
     *
309
     * @param string      $inputVariable Condition variable
310
     * @param string      $className
311
     * @param string|null $alias
312
     *
313
     * @return string Condition code
314
     */
315
    protected function buildResolverCondition(string $inputVariable, string $className, string $alias = null) : string
316
    {
317
        // Create condition branch
318
        $condition = $inputVariable . ' === \'' . $className . '\'';
319
320
        if ($alias !== null && $alias !== $className) {
321
            $condition .= '||' . $this->buildResolverCondition($inputVariable, $alias);
322
        }
323
324
        return $condition;
325
    }
326
327
    /**
328
     * Get valid class methods metadata.
329
     *
330
     * @param MethodMetadata[] $classMethodsMetadata All class methods metadata
331
     *
332
     * @return array Valid class methods metadata
333
     */
334
    protected function getValidClassMethodsMetadata(array $classMethodsMetadata)
335
    {
336
        /** @var MethodMetadata[] Gather only valid method for container */
337
        $classValidMethods = [];
338
        foreach ($classMethodsMetadata as $methodName => $methodMetadata) {
339
            // Skip constructor method and empty dependencies
340
            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...
341
                $classValidMethods[$methodName] = $methodMetadata;
342
            }
343
        }
344
345
        return $classValidMethods;
346
    }
347
348
    /**
349
     * Get valid class properties metadata.
350
     *
351
     * @param PropertyMetadata[] $classPropertiesMetadata All class properties metadata
352
     *
353
     * @return array Valid class properties metadata
354
     */
355
    protected function getValidClassPropertiesMetadata(array $classPropertiesMetadata)
356
    {
357
        /** @var PropertyMetadata[] Gather only valid property for container */
358
        $classValidProperties = [];
359
        foreach ($classPropertiesMetadata as $propertyName => $propertyMetadata) {
360
            // Skip constructor method and empty dependencies
361
            if ($propertyMetadata->dependency) {
362
                $classValidProperties[$propertyName] = $propertyMetadata;
363
            }
364
        }
365
366
        return $classValidProperties;
367
    }
368
369
    /**
370
     * Build resolving function class block.
371
     *
372
     * @param string $className Class name for new instance creation
373
     */
374
    protected function buildResolvingClassDeclaration(string $className)
375
    {
376
        $this->generator->text('new \\' . ltrim($className, '\\') . '(');
377
    }
378
379
    /**
380
     * Build constructor arguments injection.
381
     *
382
     * @param MethodMetadata[] $methodsMetaData
383
     */
384
    protected function buildConstructorDependencies(array $methodsMetaData)
385
    {
386
        // Process constructor dependencies
387
        $argumentsCount = 0;
388
        if (array_key_exists('__construct', $methodsMetaData)) {
389
            $constructorArguments = $methodsMetaData['__construct']->dependencies ?? [];
390
            $argumentsCount = count($constructorArguments);
391
            $i = 0;
392
393
            // Add indentation to move declaration arguments
394
            $this->generator->tabs++;
395
396
            // Process constructor arguments
397
            foreach ($constructorArguments as $argument => $parameterMetadata) {
398
                $this->buildResolverArgument($parameterMetadata);
399
400
                // Add comma if this is not last dependency
401
                if (++$i < $argumentsCount) {
402
                    $this->generator->text(',');
403
                }
404
            }
405
406
            // Restore indentation
407
            $this->generator->tabs--;
408
        }
409
410
        // Close declaration block, multiline if we have dependencies
411
        $argumentsCount ? $this->generator->newLine(');') : $this->generator->text(');');
412
    }
413
414
    /**
415
     * Build resolving function dependency argument.
416
     *
417
     * @param mixed $argument Dependency argument
418
     *
419
     * @throws \InvalidArgumentException On invalid argument type
420
     */
421
    protected function buildResolverArgument($argument, $textFunction = 'newLine')
422
    {
423
        switch ($this->getArgumentType($argument)) {
424
            // Call container logic for this dependency
425
            case 1:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
426
                return $this->generator->$textFunction('$this->get(\'' . $argument . '\')');
427
            // Call container logic for this dependency by alias
428
            case 2:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
429
                return $this->generator->$textFunction('$this->get(\'' . $this->classAliases[$argument] . '\')');
430
            // String variable
431
            case 3:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
432
                return $this->generator->$textFunction()->stringValue($argument);
433
            // Dependency value is array
434
            case 4:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
435
                return $this->generator->$textFunction()->arrayValue($argument);
436
        }
437
    }
438
439
    /**
440
     * Define argument type
441
     *
442
     * @param string $argument
443
     * @return int
444
     * @throws \InvalidArgumentException
445
     */
446 2
    protected function getArgumentType(string $argument) : int
447
    {
448
        // This is a dependency which invokes resolving function
449 2
        if (is_string($argument)) {
450 2
            if ($this->parentContainer !== null && $this->parentContainer->has($argument)) {
451
                return 1;
452 2
            } elseif (array_key_exists($argument, $this->classesMetadata)) {
453
                return 1;
454 2
            } elseif (array_key_exists($argument, $this->classAliases)) {
455 2
                return 2;
456
            } elseif (class_exists($argument)) { // If this argument is existing class
457
                throw new \InvalidArgumentException($argument.' class metadata is not defined');
458
            } elseif (interface_exists($argument)) { // If this argument is existing interface
459
                throw new \InvalidArgumentException($argument.' - interface dependency not resolvable');
460
            } else { // String variable
461
                return 3;
462
            }
463
        } elseif (is_array($argument)) { // Dependency value is array
464
            return 4;
465
        }
466
467
        return 0;
468
    }
469
470
    /**
471
     * Generate reflection class for private/protected methods or properties
472
     * in current scope.
473
     *
474
     * @param string             $className          Reflection class source class name
475
     * @param PropertyMetadata[] $propertiesMetadata Properties metadata
476
     * @param MethodMetadata[]   $methodsMetadata    Methods metadata
477
     * @param string             $reflectionVariable Reflection class variable name
478
     */
479
    protected function buildReflectionClass(string $className, array $propertiesMetadata, array $methodsMetadata, string $reflectionVariable)
480
    {
481
        /**
482
         * Iterate all properties and create internal scope reflection class instance if
483
         * at least one property in not public
484
         */
485 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...
486
            if (!$propertyMetadata->isPublic) {
487
                $this->generator
488
                    ->comment('Create reflection class for injecting private/protected properties and methods')
489
                    ->newLine($reflectionVariable . ' = new \ReflectionClass(\'' . $className . '\');')
490
                    ->newLine();
491
492
                return true;
493
            }
494
        }
495
496
        /**
497
         * Iterate all properties and create internal scope reflection class instance if
498
         * at least one property in not public
499
         */
500 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...
501
            if (!$methodMetadata->isPublic) {
502
                $this->generator
503
                    ->comment('Create reflection class for injecting private/protected properties and methods')
504
                    ->newLine($reflectionVariable . ' = new \ReflectionClass(\'' . $className . '\');')
505
                    ->newLine();
506
507
                return true;
508
            }
509
        }
510
511
        return false;
512
    }
513
514
    /**
515
     * Build resolving property injection declaration.
516
     *
517
     * @param string $propertyName       Target property name
518
     * @param string $dependency         Dependency class name
519
     * @param string $containerVariable  Container declaration variable name
520
     * @param string $reflectionVariable Reflection class variable name
521
     * @param bool   $isPublic           Flag if property is public
522
     */
523
    protected function buildResolverPropertyDeclaration(
524
        string $propertyName,
525
        string $dependency,
526
        string $containerVariable,
527
        string $reflectionVariable,
528
        bool $isPublic
529
    )
530
    {
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...
531
        if ($isPublic) {
532
            $this->generator
533
                ->comment('Inject public dependency for $' . $propertyName)
534
                ->newLine($containerVariable . '->' . $propertyName . ' = ');
535
            $this->buildResolverArgument($dependency, 'text');
536
            $this->generator->text(';');
537
        } else {
538
            $this->generator
539
                ->comment('Inject private dependency for $' . $propertyName)
540
                ->newLine('$property = ' . $reflectionVariable . '->getProperty(\'' . $propertyName . '\');')
541
                ->newLine('$property->setAccessible(true);')
542
                ->newLine('$property->setValue(')
543
                ->increaseIndentation()
544
                ->newLine($containerVariable . ',');
545
546
            $this->buildResolverArgument($dependency);
547
548
            $this->generator
549
                ->decreaseIndentation()
550
                ->newLine(');')
551
                ->newLine('$property->setAccessible(false);')
552
                ->newLine();
553
        }
554
    }
555
556
    /**
557
     * Build resolving method injection declaration.
558
     *
559
     * @param array  $dependencies       Collection of method dependencies
560
     * @param string $methodName         Method name
561
     * @param string $containerVariable  Container declaration variable name
562
     * @param string $reflectionVariable Reflection class variable name
563
     * @param bool   $isPublic           Flag if method is public
564
     */
565
    protected function buildResolverMethodDeclaration(
566
        array $dependencies,
567
        string $methodName,
568
        string $containerVariable,
569
        string $reflectionVariable,
570
        bool $isPublic
571
    )
572
    {
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...
573
        // Get method arguments
574
        $argumentsCount = count($dependencies);
575
576
        $this->generator->comment('Invoke ' . $methodName . '() and pass dependencies(y)');
577
578
        if ($isPublic) {
579
            $this->generator->newLine($containerVariable . '->' . $methodName . '(')->increaseIndentation();
580
        } else {
581
            $this->generator
582
                ->newLine('$method = ' . $reflectionVariable . '->getMethod(\'' . $methodName . '\');')
583
                ->newLine('$method->setAccessible(true);')
584
                ->newLine('$method->invoke(')
585
                ->increaseIndentation()
586
                ->newLine($containerVariable . ',');
587
        }
588
589
        $i = 0;
590
        // Iterate method arguments
591
        foreach ($dependencies as $argument => $dependency) {
592
            // Add dependencies
593
            $this->buildResolverArgument($dependency);
594
595
            // Add comma if this is not last dependency
596
            if (++$i < $argumentsCount) {
597
                $this->generator->text(',');
598
            }
599
        }
600
601
        $this->generator->decreaseIndentation()->newLine(');');
602
    }
603
}
604