Issues (63)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Builder.php (13 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
     */
54
    protected $generator;
55
56
    /** @var string Resolver function name */
57
    protected $resolverFunction;
58
59
    /**
60
     * Container builder constructor.
61
     *
62
     * @param Generator       $generator     PHP code generator
63
     * @param ClassMetadata[] $classMetadata Collection of classes metadata for container
0 ignored issues
show
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...
64
     */
65
    public function __construct(Generator $generator)
66
    {
67
        $this->generator = $generator;
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73
    public function build(array $classesMetadata, $containerClass = 'Container', $namespace = '', ContainerInterface $parentContainer = null)
74
    {
75
        $this->classesMetadata = $this->processClassMetadata($classesMetadata);
76
        $this->parentContainer = $parentContainer;
77
78
        // Build dependency injection container function name
79
        $this->resolverFunction = uniqid(self::DI_FUNCTION_PREFIX);
80
81
        $containerDependencies = [];
82
        foreach ($classesMetadata as $classMetadata) {
83
            $className = $classMetadata->className;
84
            // Store inner dependencies
85
            if (array_key_exists('__construct', $classMetadata->methodsMetadata)) {
86
                $containerDependencies[$className] = array_values($classMetadata->methodsMetadata['__construct']->dependencies ?? []);
87
            }
88
        }
89
90
        $this->generator
91
            ->text('<?php declare(strict_types = 1);')
92
            ->newLine()
93
            ->defNamespace($namespace)
94
            ->multiComment(['Application container'])
95
            ->defClass($containerClass, '\\' . Container::class)
96
            ->multiComment(['@var array Collection of service instances'])
97
            ->defClassFunction('__construct', 'public', [], ['Container constructor'])
98
            ->newLine('$this->dependencies = ')->arrayValue($containerDependencies)->text(';')
99
            ->newLine('$this->aliases = ')->arrayValue($this->classAliases)->text(';')
100
            ->newLine('$this->scopes = ')->arrayValue($this->scopes)->text(';')
101
            ->newLine('$this->services = ')->arrayValue($this->scopes[self::SCOPE_SERVICES])->text(';')
102
            ->endClassFunction()
103
            ->defClassFunction('logic', 'protected', ['$dependency'], ['{@inheritdoc}'])
104
            ->newLine('return $this->' . $this->resolverFunction . '($dependency);')
105
            ->endClassFunction();
106
107
        foreach ($this->classesMetadata as $classMetadata) {
108
            $className = $classMetadata->className;
109
            $dependencyName = $classMetadata->name ?? $className;
110
111
            // Generate camel case getter method
112
            $camelMethodName = 'get' . str_replace(' ', '', ucwords(ucfirst(str_replace(['\\', '_'], ' ', $dependencyName))));
113
114
            $this->generator
115
                ->defClassFunction($camelMethodName, 'public', [], ['@return ' . '\\'.ltrim($className, '\\') . ' Get ' . $dependencyName . ' instance'])
116
                ->newLine('return $this->' . $this->resolverFunction . '(\'' . $dependencyName . '\');')
117
                ->endClassFunction();
118
        }
119
120
        // Build di container function and add to container class and return class code
121
        $this->buildDependencyResolver($this->resolverFunction);
122
123
        return $this->generator
124
            ->endClass()
125
            ->flush();
126
    }
127
128
    /**
129
     * Read class metadata and fill internal collections.
130
     *
131
     * @param ClassMetadata[] $classesMetadata
132
     * @return ClassMetadata[] Processed class metadata
133
     */
134
    public function processClassMetadata(array $classesMetadata) : array
135
    {
136
        /** @var ClassMetadata[] $processedClassesMetadata */
137
        $processedClassesMetadata = [];
138
139
        // Read all classes in given file
140
        foreach ($classesMetadata as $classMetadata) {
141
            // Store by metadata name as alias
142
            $this->classAliases[$classMetadata->className] = $classMetadata->name;
143
144
            // Store class in defined scopes
145
            foreach ($classMetadata->scopes as $scope) {
146
                $this->scopes[$scope][$classMetadata->name] = $classMetadata->className;
147
            }
148
            $processedClassesMetadata[$classMetadata->name] = $classMetadata;
149
        }
150
151
        $dependencies = [];
152
        foreach ($processedClassesMetadata as $alias => $classMetadata) {
153
            if (count($classMetadata->methodsMetadata)) {
154
                foreach ($classMetadata->methodsMetadata as $methodMetadata) {
155
                    foreach ($methodMetadata->dependencies as $dependency) {
156
                        if (in_array($this->getArgumentType($dependency), [1, 2], true)) {
157
                            $dependencies[] = $dependency;
158
                        }
159
                    }
160
                }
161
                $dependencies[] = $classMetadata->name;
162
            }
163
            if (count($classMetadata->propertiesMetadata)) {
164
                foreach ($classMetadata->propertiesMetadata as $propertyMetadata) {
165
                    $dependencies[] = $propertyMetadata->dependency;
166
                }
167
                $dependencies[] = $classMetadata->name;
168
            }
169
            if (count($classMetadata->scopes)) {
170
                $dependencies[] = $classMetadata->name;
171
            }
172
        }
173
        $dependencies = array_unique($dependencies);
174
175
        foreach ($processedClassesMetadata as $alias => $classMetadata) {
176
            if (!in_array($alias, $dependencies, true)) {
177
                unset($processedClassesMetadata[$alias]);
178
            }
179
        }
180
        $this->generator->flush();
181
182
        return $processedClassesMetadata;
183
    }
184
185
    /**
186
     * Build dependency resolving function.
187
     *
188
     * @param string $functionName Function name
189
     *
190
     * @throws \InvalidArgumentException
191
     */
192
    protected function buildDependencyResolver($functionName)
193
    {
194
        $inputVariable = '$aliasOrClassName';
195
        $this->generator
196
            ->defClassFunction($functionName, 'protected', [$inputVariable], ['Dependency resolving function'])
197
            //->defVar('static ' . self::DI_FUNCTION_SERVICES . ' = []')
198
            ->newLine();
199
200
        // Generate all container and delegate conditions
201
        $this->generateConditions($inputVariable, false);
202
203
        // Add method not found
204
        $this->generator->endIfCondition()->endFunction();
205
    }
206
207
    /**
208
     * Generate logic conditions and their implementation for container and its delegates.
209
     *
210
     * @param string     $inputVariable Input condition parameter variable name
211
     * @param bool|false $started       Flag if condition branching has been started
212
     */
213
    public function generateConditions($inputVariable = '$alias', $started = false)
214
    {
215
        // Iterate all container dependencies
216
        foreach ($this->classesMetadata as $classMetadata) {
217
            $className = $classMetadata->className;
218
            // Generate condition statement to define if this class is needed
219
            $conditionFunc = !$started ? 'defIfCondition' : 'defElseIfCondition';
220
221
            // Output condition branch
222
            $this->generator->$conditionFunc(
223
                $this->buildResolverCondition($inputVariable, $className, $classMetadata->name)
224
            );
225
226
            // Define if this class has service scope
227
            $isService = in_array($className, $this->scopes[self::SCOPE_SERVICES], true);
228
229
            /** @var MethodMetadata[] Gather only valid method for container */
230
            $classValidMethods = $this->getValidClassMethodsMetadata($classMetadata->methodsMetadata);
231
232
            /** @var PropertyMetadata[] Gather only valid property for container */
233
            $classValidProperties = $this->getValidClassPropertiesMetadata($classMetadata->propertiesMetadata);
234
235
            // Define class or service variable
236
            $staticContainerName = $isService
237
                ? '$this->' . self::DI_FUNCTION_SERVICES . '[\'' . $classMetadata->name . '\']'
238
                : '$temp';
239
240
            if ($isService) {
241
                // Check if dependency was instantiated
242
                $this->generator->defIfCondition('!array_key_exists(\'' . $classMetadata->name . '\', $this->' . self::DI_FUNCTION_SERVICES . ')');
243
            }
244
245
            if (count($classValidMethods) || count($classValidProperties)) {
246
                $this->generator->newLine($staticContainerName . ' = ');
247
                $this->buildResolvingClassDeclaration($className);
248
                $this->buildConstructorDependencies($classMetadata->methodsMetadata);
249
250
                // Internal scope reflection variable
251
                $reflectionVariable = '$reflectionClass';
252
253
                $this->buildReflectionClass($className, $classValidProperties, $classValidMethods, $reflectionVariable);
254
255
                // Process class properties
256
                foreach ($classValidProperties as $property) {
257
                    // If such property has the dependency
258
                    if ($property->dependency) {
259
                        // Set value via refection
260
                        $this->buildResolverPropertyDeclaration(
261
                            $property->name,
262
                            $property->dependency,
263
                            $staticContainerName,
264
                            $reflectionVariable,
265
                            $property->isPublic
266
                        );
267
                    }
268
                }
269
270
                /** @var MethodMetadata $methodMetadata */
271
                foreach ($classValidMethods as $methodName => $methodMetadata) {
272
                    $this->buildResolverMethodDeclaration(
273
                        $methodMetadata->dependencies,
274
                        $methodName,
275
                        $staticContainerName,
276
                        $reflectionVariable,
277
                        $methodMetadata->isPublic
278
                    );
279
                }
280
281
                if ($isService) {
282
                    $this->generator->endIfCondition();
283
                }
284
285
                $this->generator->newLine()->newLine('return ' . $staticContainerName . ';');
286
            } else {
287
                if ($isService) {
288
                    $this->generator->newLine($staticContainerName.' = ');
289
                    $this->buildResolvingClassDeclaration($className);
290
                    $this->buildConstructorDependencies($classMetadata->methodsMetadata);
291
                    $this->generator->endIfCondition()->newLine('return ' . $staticContainerName . ';');
292
                } else {
293
                    $this->generator->newLine('return ');
294
                    $this->buildResolvingClassDeclaration($className);
295
                    $this->buildConstructorDependencies($classMetadata->methodsMetadata);
296
                }
297
0 ignored issues
show
Blank line found at end of control structure
Loading history...
298
            }
299
300
            // Set flag that condition is started
301
            $started = true;
302
        }
303
    }
304
305
    /**
306
     * Build resolving function condition.
307
     *
308
     * @param string      $inputVariable Condition variable
309
     * @param string      $className
310
     * @param string|null $alias
311
     *
312
     * @return string Condition code
313
     */
314
    protected function buildResolverCondition(string $inputVariable, string $className, string $alias = null) : string
315
    {
316
        // Create condition branch
317
        $condition = $inputVariable . ' === \'' . $className . '\'';
318
319
        if ($alias !== null && $alias !== $className) {
320
            $condition .= '||' . $this->buildResolverCondition($inputVariable, $alias);
321
        }
322
323
        return $condition;
324
    }
325
326
    /**
327
     * Get valid class methods metadata.
328
     *
329
     * @param MethodMetadata[] $classMethodsMetadata All class methods metadata
330
     *
331
     * @return array Valid class methods metadata
332
     */
333
    protected function getValidClassMethodsMetadata(array $classMethodsMetadata)
334
    {
335
        /** @var MethodMetadata[] Gather only valid method for container */
336
        $classValidMethods = [];
337
        foreach ($classMethodsMetadata as $methodName => $methodMetadata) {
338
            // Skip constructor method and empty dependencies
339
            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...
340
                $classValidMethods[$methodName] = $methodMetadata;
341
            }
342
        }
343
344
        return $classValidMethods;
345
    }
346
347
    /**
348
     * Get valid class properties metadata.
349
     *
350
     * @param PropertyMetadata[] $classPropertiesMetadata All class properties metadata
351
     *
352
     * @return array Valid class properties metadata
353
     */
354
    protected function getValidClassPropertiesMetadata(array $classPropertiesMetadata)
355
    {
356
        /** @var PropertyMetadata[] Gather only valid property for container */
357
        $classValidProperties = [];
358
        foreach ($classPropertiesMetadata as $propertyName => $propertyMetadata) {
359
            // Skip constructor method and empty dependencies
360
            if ($propertyMetadata->dependency) {
361
                $classValidProperties[$propertyName] = $propertyMetadata;
362
            }
363
        }
364
365
        return $classValidProperties;
366
    }
367
368
    /**
369
     * Build resolving function class block.
370
     *
371
     * @param string $className Class name for new instance creation
372
     */
373
    protected function buildResolvingClassDeclaration(string $className)
374
    {
375
        $this->generator->text('new \\' . ltrim($className, '\\') . '(');
376
    }
377
378
    /**
379
     * Build constructor arguments injection.
380
     *
381
     * @param MethodMetadata[] $methodsMetaData
382
     */
383
    protected function buildConstructorDependencies(array $methodsMetaData)
384
    {
385
        // Process constructor dependencies
386
        $argumentsCount = 0;
387
        if (array_key_exists('__construct', $methodsMetaData)) {
388
            $constructorArguments = $methodsMetaData['__construct']->dependencies ?? [];
389
            $argumentsCount = count($constructorArguments);
390
            $i = 0;
391
392
            // Add indentation to move declaration arguments
393
            $this->generator->tabs++;
394
395
            if ($methodsMetaData['__construct'] && isset($methodsMetaData['__construct']->classMetadata)) {
396
                $className = $methodsMetaData['__construct']->classMetadata->className;
397
                $parameters = (new \ReflectionMethod($className, '__construct'))->getParameters();
398
                foreach ($parameters as $parameter) {
399
                    if (isset($constructorArguments[$parameter->getName()])) {
0 ignored issues
show
Consider using $parameter->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
400
                        $this->buildResolverArgument($constructorArguments[$parameter->getName()]);
0 ignored issues
show
Consider using $parameter->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
401
                        // Add comma if this is not last dependency
402
                        if (++$i < $argumentsCount) {
403
                            $this->generator->text(',');
404
                        }
405
                    }
406
                }
407
            }
408
409
            // Process constructor arguments
410
//            foreach ($constructorArguments as $argument => $parameterMetadata) {
411
//                $this->buildResolverArgument($parameterMetadata);
412
//
413
//                // Add comma if this is not last dependency
414
//                if (++$i < $argumentsCount) {
415
//                    $this->generator->text(',');
416
//                }
417
//            }
418
419
            // Restore indentation
420
            $this->generator->tabs--;
421
        }
422
423
        // Close declaration block, multiline if we have dependencies
424
        $argumentsCount ? $this->generator->newLine(');') : $this->generator->text(');');
425
    }
426
427
    /**
428
     * Build resolving function dependency argument.
429
     *
430
     * @param mixed $argument Dependency argument
431
     *
432
     * @throws \InvalidArgumentException On invalid argument type
433
     */
434
    protected function buildResolverArgument($argument, $textFunction = 'newLine')
435
    {
436
        switch ($this->getArgumentType($argument)) {
437
            // Call container logic for this dependency
438
            case 1:
0 ignored issues
show
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...
439
                return $this->generator->$textFunction('$this->get(\'' . $argument . '\')');
440
            // Call container logic for this dependency by alias
441
            case 2:
0 ignored issues
show
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...
442
                return $this->generator->$textFunction('$this->get(\'' . $this->classAliases[$argument] . '\')');
443
            // String variable
444
            case 3:
0 ignored issues
show
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...
445
                return $this->generator->$textFunction()->stringValue($argument);
446
            // Dependency value is array
447
            case 4:
0 ignored issues
show
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...
448
                return $this->generator->$textFunction()->arrayValue($argument);
449
        }
450
    }
451
452
    /**
453
     * Define argument type
454
     *
455
     * @param mixed $argument
456
     * @return int
457
     * @throws \InvalidArgumentException
458
     */
459
    protected function getArgumentType($argument) : int
460
    {
461
        // This is a dependency which invokes resolving function
462
        if (is_string($argument)) {
463
            if ($this->parentContainer !== null && $this->parentContainer->has($argument)) {
464
                return 1;
465
            } elseif (array_key_exists($argument, $this->classesMetadata)) {
466
                return 1;
467
            } elseif (array_key_exists($argument, $this->classAliases)) {
468
                return 2;
469
            } elseif (class_exists($argument)) { // If this argument is existing class
470
                throw new \InvalidArgumentException($argument.' class metadata is not defined');
471
            } elseif (interface_exists($argument)) { // If this argument is existing interface
472
                throw new \InvalidArgumentException($argument.' - interface dependency not resolvable');
473
            } else { // String variable
474
                return 3;
475
            }
476
        } elseif (is_array($argument)) { // Dependency value is array
477
            return 4;
478
        }
479
480
        return 0;
481
    }
482
483
    /**
484
     * Generate reflection class for private/protected methods or properties
485
     * in current scope.
486
     *
487
     * @param string             $className          Reflection class source class name
488
     * @param PropertyMetadata[] $propertiesMetadata Properties metadata
489
     * @param MethodMetadata[]   $methodsMetadata    Methods metadata
490
     * @param string             $reflectionVariable Reflection class variable name
491
     */
492
    protected function buildReflectionClass(string $className, array $propertiesMetadata, array $methodsMetadata, string $reflectionVariable)
493
    {
494
        /**
495
         * Iterate all properties and create internal scope reflection class instance if
496
         * at least one property in not public
497
         */
498 View Code Duplication
        foreach ($propertiesMetadata as $propertyMetadata) {
0 ignored issues
show
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...
499
            if (!$propertyMetadata->isPublic) {
500
                $this->generator
501
                    ->comment('Create reflection class for injecting private/protected properties and methods')
502
                    ->newLine($reflectionVariable . ' = new \ReflectionClass(\'' . $className . '\');')
503
                    ->newLine();
504
505
                return true;
506
            }
507
        }
508
509
        /**
510
         * Iterate all properties and create internal scope reflection class instance if
511
         * at least one property in not public
512
         */
513 View Code Duplication
        foreach ($methodsMetadata as $methodMetadata) {
0 ignored issues
show
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...
514
            if (!$methodMetadata->isPublic) {
515
                $this->generator
516
                    ->comment('Create reflection class for injecting private/protected properties and methods')
517
                    ->newLine($reflectionVariable . ' = new \ReflectionClass(\'' . $className . '\');')
518
                    ->newLine();
519
520
                return true;
521
            }
522
        }
523
524
        return false;
525
    }
526
527
    /**
528
     * Build resolving property injection declaration.
529
     *
530
     * @param string $propertyName       Target property name
531
     * @param string $dependency         Dependency class name
532
     * @param string $containerVariable  Container declaration variable name
533
     * @param string $reflectionVariable Reflection class variable name
534
     * @param bool   $isPublic           Flag if property is public
535
     */
536
    protected function buildResolverPropertyDeclaration(
537
        string $propertyName,
538
        string $dependency,
539
        string $containerVariable,
540
        string $reflectionVariable,
541
        bool $isPublic
542
    )
543
    {
0 ignored issues
show
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
544
        if ($isPublic) {
545
            $this->generator
546
                ->comment('Inject public dependency for $' . $propertyName)
547
                ->newLine($containerVariable . '->' . $propertyName . ' = ');
548
            $this->buildResolverArgument($dependency, 'text');
549
            $this->generator->text(';');
550
        } else {
551
            $this->generator
552
                ->comment('Inject private dependency for $' . $propertyName)
553
                ->newLine('$property = ' . $reflectionVariable . '->getProperty(\'' . $propertyName . '\');')
554
                ->newLine('$property->setAccessible(true);')
555
                ->newLine('$property->setValue(')
556
                ->increaseIndentation()
557
                ->newLine($containerVariable . ',');
558
559
            $this->buildResolverArgument($dependency);
560
561
            $this->generator
562
                ->decreaseIndentation()
563
                ->newLine(');')
564
                ->newLine('$property->setAccessible(false);')
565
                ->newLine();
566
        }
567
    }
568
569
    /**
570
     * Build resolving method injection declaration.
571
     *
572
     * @param array  $dependencies       Collection of method dependencies
573
     * @param string $methodName         Method name
574
     * @param string $containerVariable  Container declaration variable name
575
     * @param string $reflectionVariable Reflection class variable name
576
     * @param bool   $isPublic           Flag if method is public
577
     */
578
    protected function buildResolverMethodDeclaration(
579
        array $dependencies,
580
        string $methodName,
581
        string $containerVariable,
582
        string $reflectionVariable,
583
        bool $isPublic
584
    )
585
    {
0 ignored issues
show
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
586
        // Get method arguments
587
        $argumentsCount = count($dependencies);
588
589
        $this->generator->comment('Invoke ' . $methodName . '() and pass dependencies(y)');
590
591
        if ($isPublic) {
592
            $this->generator->newLine($containerVariable . '->' . $methodName . '(')->increaseIndentation();
593
        } else {
594
            $this->generator
595
                ->newLine('$method = ' . $reflectionVariable . '->getMethod(\'' . $methodName . '\');')
596
                ->newLine('$method->setAccessible(true);')
597
                ->newLine('$method->invoke(')
598
                ->increaseIndentation()
599
                ->newLine($containerVariable . ',');
600
        }
601
602
        $i = 0;
603
        // Iterate method arguments
604
        foreach ($dependencies as $argument => $dependency) {
605
            // Add dependencies
606
            $this->buildResolverArgument($dependency);
607
608
            // Add comma if this is not last dependency
609
            if (++$i < $argumentsCount) {
610
                $this->generator->text(',');
611
            }
612
        }
613
614
        $this->generator->decreaseIndentation()->newLine(');');
615
    }
616
}
617