Completed
Push — master ( 8cb5f0...3a354b )
by Vitaly
03:08
created

Builder::generateConditions()   C

Complexity

Conditions 12
Paths 33

Size

Total Lines 91
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 12.9266

Importance

Changes 0
Metric Value
dl 0
loc 91
ccs 35
cts 43
cp 0.8139
rs 5.034
c 0
b 0
f 0
cc 12
eloc 49
nc 33
nop 2
crap 12.9266

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 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 2
        $this->parentContainer = $parentContainer;
78
79
        // Build dependency injection container function name
80 2
        $this->resolverFunction = uniqid(self::DI_FUNCTION_PREFIX);
81
82 2
        $containerDependencies = [];
83 2
        foreach ($classesMetadata as $classMetadata) {
84 2
            $className = $classMetadata->className;
85
            // Store inner dependencies
86 2
            if (array_key_exists('__construct', $classMetadata->methodsMetadata)) {
87 2
                $containerDependencies[$className] = array_values($classMetadata->methodsMetadata['__construct']->dependencies ?? []);
88
            }
89
        }
90
91 2
        $this->generator
92 2
            ->text('<?php declare(strict_types = 1);')
93 2
            ->newLine()
94 2
            ->defNamespace($namespace)
95 2
            ->multiComment(['Application container'])
96 2
            ->defClass($containerClass, '\\' . Container::class)
97 2
            ->multiComment(['@var array Collection of service instances'])
98 2
            ->defClassFunction('__construct', 'public', [], ['Container constructor'])
99 2
            ->newLine('$this->dependencies = ')->arrayValue($containerDependencies)->text(';')
100 2
            ->newLine('$this->aliases = ')->arrayValue($this->classAliases)->text(';')
101 2
            ->newLine('$this->scopes = ')->arrayValue($this->scopes)->text(';')
102 2
            ->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 2
            ->endClassFunction()
104 2
            ->defClassFunction('logic', 'protected', ['$dependency'], ['{@inheritdoc}'])
105 2
            ->newLine('return $this->' . $this->resolverFunction . '($dependency);')
106 2
            ->endClassFunction();
107
108 2
        foreach ($classesMetadata as $classMetadata) {
109 2
            $className = $classMetadata->className;
110 2
            $dependencyName = $classMetadata->name ?? $className;
111
112
            // Generate camel case getter method
113 2
            $camelMethodName = 'get' . str_replace(' ', '', ucwords(ucfirst(str_replace(['\\', '_'], ' ', $dependencyName))));
114
115 2
            $this->generator
116 2
                ->defClassFunction($camelMethodName, 'public', [], ['@return ' . '\\'.ltrim($className, '\\') . ' Get ' . $dependencyName . ' instance'])
117 2
                ->newLine('return $this->' . $this->resolverFunction . '(\'' . $dependencyName . '\');')
118 2
                ->endClassFunction();
119
        }
120
121
        // Build di container function and add to container class and return class code
122 2
        $this->buildDependencyResolver($this->resolverFunction);
123
124 2
        return $this->generator
125 2
            ->endClass()
126 2
            ->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 2
                $dependencies[] = $classMetadata->name;
163
            }
164 2
            if (count($classMetadata->propertiesMetadata)) {
165 2
                foreach ($classMetadata->propertiesMetadata as $propertyMetadata) {
166 2
                    $dependencies[] = $propertyMetadata->dependency;
167
                }
168 2
                $dependencies[] = $classMetadata->name;
169
            }
170 2
            if (count($classMetadata->scopes)) {
171 2
                $dependencies[] = $classMetadata->name;
172
            }
173
        }
174 2
        $dependencies = array_unique($dependencies);
175
176 2
        foreach ($processedClassesMetadata as $alias => $classMetadata) {
177 2
            if (!in_array($alias, $dependencies, true)) {
178 2
                unset($processedClassesMetadata[$alias]);
179
            }
180
        }
181 2
        $this->generator->flush();
182
183 2
        return $processedClassesMetadata;
184
    }
185
186
    /**
187
     * Build dependency resolving function.
188
     *
189
     * @param string $functionName Function name
190
     *
191
     * @throws \InvalidArgumentException
192
     */
193 2
    protected function buildDependencyResolver($functionName)
194
    {
195 2
        $inputVariable = '$aliasOrClassName';
196 2
        $this->generator
197 2
            ->defClassFunction($functionName, 'protected', [$inputVariable], ['Dependency resolving function'])
198
            //->defVar('static ' . self::DI_FUNCTION_SERVICES . ' = []')
199 2
            ->newLine();
200
201
        // Generate all container and delegate conditions
202 2
        $this->generateConditions($inputVariable, false);
203
204
        // Add method not found
205 2
        $this->generator->endIfCondition()->endFunction();
206 2
    }
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 2
    public function generateConditions($inputVariable = '$alias', $started = false)
215
    {
216
        // Iterate all container dependencies
217 2
        foreach ($this->classesMetadata as $classMetadata) {
218 2
            $className = $classMetadata->className;
219
            // Generate condition statement to define if this class is needed
220 2
            $conditionFunc = !$started ? 'defIfCondition' : 'defElseIfCondition';
221
222
            // Output condition branch
223 2
            $this->generator->$conditionFunc(
224 2
                $this->buildResolverCondition($inputVariable, $className, $classMetadata->name)
225
            );
226
227
            // Define if this class has service scope
228 2
            $isService = in_array($className, $this->scopes[self::SCOPE_SERVICES], true);
229
230
            /** @var MethodMetadata[] Gather only valid method for container */
231 2
            $classValidMethods = $this->getValidClassMethodsMetadata($classMetadata->methodsMetadata);
232
233
            /** @var PropertyMetadata[] Gather only valid property for container */
234 2
            $classValidProperties = $this->getValidClassPropertiesMetadata($classMetadata->propertiesMetadata);
235
236
            // Define class or service variable
237 2
            $staticContainerName = $isService
238 2
                ? '$this->' . self::DI_FUNCTION_SERVICES . '[\'' . $classMetadata->name . '\']'
239 2
                : '$temp';
240
241 2
            if ($isService) {
242
                // Check if dependency was instantiated
243 2
                $this->generator->defIfCondition('!array_key_exists(\'' . $classMetadata->name . '\', $this->' . self::DI_FUNCTION_SERVICES . ')');
244
            }
245
246 2
            if (count($classValidMethods) || count($classValidProperties)) {
247 2
                $this->generator->newLine($staticContainerName . ' = ');
248 2
                $this->buildResolvingClassDeclaration($className);
249 2
                $this->buildConstructorDependencies($classMetadata->methodsMetadata);
250
251
                // Internal scope reflection variable
252 2
                $reflectionVariable = '$reflectionClass';
253
254 2
                $this->buildReflectionClass($className, $classValidProperties, $classValidMethods, $reflectionVariable);
255
256
                // Process class properties
257 2
                foreach ($classValidProperties as $property) {
258
                    // If such property has the dependency
259 2
                    if ($property->dependency) {
260
                        // Set value via refection
261 2
                        $this->buildResolverPropertyDeclaration(
262 2
                            $property->name,
263 2
                            $property->dependency,
264
                            $staticContainerName,
265
                            $reflectionVariable,
266 2
                            $property->isPublic
267
                        );
268
                    }
269
                }
270
271
                /** @var MethodMetadata $methodMetadata */
272 2
                foreach ($classValidMethods as $methodName => $methodMetadata) {
273 2
                    $this->buildResolverMethodDeclaration(
274 2
                        $methodMetadata->dependencies,
275
                        $methodName,
276
                        $staticContainerName,
277
                        $reflectionVariable,
278 2
                        $methodMetadata->isPublic
279
                    );
280
                }
281
282 2
                if ($isService) {
283 2
                    $this->generator->endIfCondition();
284
                }
285
286 2
                $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 2
            $started = true;
303
        }
304 2
    }
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 2
    protected function buildResolverCondition(string $inputVariable, string $className, string $alias = null) : string
316
    {
317
        // Create condition branch
318 2
        $condition = $inputVariable . ' === \'' . $className . '\'';
319
320 2
        if ($alias !== null && $alias !== $className) {
321 2
            $condition .= '||' . $this->buildResolverCondition($inputVariable, $alias);
322
        }
323
324 2
        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 2
    protected function getValidClassMethodsMetadata(array $classMethodsMetadata)
335
    {
336
        /** @var MethodMetadata[] Gather only valid method for container */
337 2
        $classValidMethods = [];
338 2
        foreach ($classMethodsMetadata as $methodName => $methodMetadata) {
339
            // Skip constructor method and empty dependencies
340 2
            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 2
                $classValidMethods[$methodName] = $methodMetadata;
342
            }
343
        }
344
345 2
        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 2
    protected function getValidClassPropertiesMetadata(array $classPropertiesMetadata)
356
    {
357
        /** @var PropertyMetadata[] Gather only valid property for container */
358 2
        $classValidProperties = [];
359 2
        foreach ($classPropertiesMetadata as $propertyName => $propertyMetadata) {
360
            // Skip constructor method and empty dependencies
361 2
            if ($propertyMetadata->dependency) {
362 2
                $classValidProperties[$propertyName] = $propertyMetadata;
363
            }
364
        }
365
366 2
        return $classValidProperties;
367
    }
368
369
    /**
370
     * Build resolving function class block.
371
     *
372
     * @param string $className Class name for new instance creation
373
     */
374 2
    protected function buildResolvingClassDeclaration(string $className)
375
    {
376 2
        $this->generator->text('new \\' . ltrim($className, '\\') . '(');
377 2
    }
378
379
    /**
380
     * Build constructor arguments injection.
381
     *
382
     * @param MethodMetadata[] $methodsMetaData
383
     */
384 2
    protected function buildConstructorDependencies(array $methodsMetaData)
385
    {
386
        // Process constructor dependencies
387 2
        $argumentsCount = 0;
388 2
        if (array_key_exists('__construct', $methodsMetaData)) {
389 2
            $constructorArguments = $methodsMetaData['__construct']->dependencies ?? [];
390 2
            $argumentsCount = count($constructorArguments);
391 2
            $i = 0;
392
393
            // Add indentation to move declaration arguments
394 2
            $this->generator->tabs++;
395
396
            // Process constructor arguments
397 2
            foreach ($constructorArguments as $argument => $parameterMetadata) {
398 2
                $this->buildResolverArgument($parameterMetadata);
399
400
                // Add comma if this is not last dependency
401 2
                if (++$i < $argumentsCount) {
402 2
                    $this->generator->text(',');
403
                }
404
            }
405
406
            // Restore indentation
407 2
            $this->generator->tabs--;
408
        }
409
410
        // Close declaration block, multiline if we have dependencies
411 2
        $argumentsCount ? $this->generator->newLine(');') : $this->generator->text(');');
412 2
    }
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 2
    protected function buildResolverArgument($argument, $textFunction = 'newLine')
422
    {
423 2
        switch ($this->getArgumentType($argument)) {
424
            // Call container logic for this dependency
425 2
            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 2
            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 2
                return $this->generator->$textFunction('$this->get(\'' . $this->classAliases[$argument] . '\')');
430
            // String variable
431 2
            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 2
                return $this->generator->$textFunction()->stringValue($argument);
433
            // Dependency value is array
434 2
            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 2
                return $this->generator->$textFunction()->arrayValue($argument);
436
        }
437
    }
438
439
    /**
440
     * Define argument type
441
     *
442
     * @param mixed $argument
443
     * @return int
444
     * @throws \InvalidArgumentException
445
     */
446 2
    protected function getArgumentType($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 2
            } elseif (class_exists($argument)) { // If this argument is existing class
457
                throw new \InvalidArgumentException($argument.' class metadata is not defined');
458 2
            } elseif (interface_exists($argument)) { // If this argument is existing interface
459
                throw new \InvalidArgumentException($argument.' - interface dependency not resolvable');
460
            } else { // String variable
461 2
                return 3;
462
            }
463 2
        } elseif (is_array($argument)) { // Dependency value is array
464 2
            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 2
    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 2 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 2
            if (!$propertyMetadata->isPublic) {
487 2
                $this->generator
488 2
                    ->comment('Create reflection class for injecting private/protected properties and methods')
489 2
                    ->newLine($reflectionVariable . ' = new \ReflectionClass(\'' . $className . '\');')
490 2
                    ->newLine();
491
492 2
                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 2 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 2
        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 2
    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 2
        if ($isPublic) {
532 2
            $this->generator
533 2
                ->comment('Inject public dependency for $' . $propertyName)
534 2
                ->newLine($containerVariable . '->' . $propertyName . ' = ');
535 2
            $this->buildResolverArgument($dependency, 'text');
536 2
            $this->generator->text(';');
537
        } else {
538 2
            $this->generator
539 2
                ->comment('Inject private dependency for $' . $propertyName)
540 2
                ->newLine('$property = ' . $reflectionVariable . '->getProperty(\'' . $propertyName . '\');')
541 2
                ->newLine('$property->setAccessible(true);')
542 2
                ->newLine('$property->setValue(')
543 2
                ->increaseIndentation()
544 2
                ->newLine($containerVariable . ',');
545
546 2
            $this->buildResolverArgument($dependency);
547
548 2
            $this->generator
549 2
                ->decreaseIndentation()
550 2
                ->newLine(');')
551 2
                ->newLine('$property->setAccessible(false);')
552 2
                ->newLine();
553
        }
554 2
    }
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 2
    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 2
        $argumentsCount = count($dependencies);
575
576 2
        $this->generator->comment('Invoke ' . $methodName . '() and pass dependencies(y)');
577
578 2
        if ($isPublic) {
579 2
            $this->generator->newLine($containerVariable . '->' . $methodName . '(')->increaseIndentation();
580
        } else {
581 2
            $this->generator
582 2
                ->newLine('$method = ' . $reflectionVariable . '->getMethod(\'' . $methodName . '\');')
583 2
                ->newLine('$method->setAccessible(true);')
584 2
                ->newLine('$method->invoke(')
585 2
                ->increaseIndentation()
586 2
                ->newLine($containerVariable . ',');
587
        }
588
589 2
        $i = 0;
590
        // Iterate method arguments
591 2
        foreach ($dependencies as $argument => $dependency) {
592
            // Add dependencies
593 2
            $this->buildResolverArgument($dependency);
594
595
            // Add comma if this is not last dependency
596 2
            if (++$i < $argumentsCount) {
597 2
                $this->generator->text(',');
598
            }
599
        }
600
601 2
        $this->generator->decreaseIndentation()->newLine(');');
602 2
    }
603
}
604