Completed
Pull Request — master (#392)
by Witold
08:14
created

Constructor::generateMethod()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 24
ccs 16
cts 16
cp 1
rs 8.9713
cc 2
eloc 17
nc 2
nop 2
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ProxyManager\ProxyGenerator\ValueHolder\MethodGenerator;
6
7
use ProxyManager\Generator\MethodGenerator;
8
use ProxyManager\ProxyGenerator\Util\Properties;
9
use ProxyManager\ProxyGenerator\Util\UnsetPropertiesGenerator;
10
use ReflectionClass;
11
use Zend\Code\Generator\ParameterGenerator;
12
use Zend\Code\Generator\PropertyGenerator;
13
use Zend\Code\Reflection\MethodReflection;
14
15
/**
16
 * The `__construct` implementation for lazy loading proxies
17
 *
18
 * @author Marco Pivetta <[email protected]>
19
 * @license MIT
20
 */
21
class Constructor extends MethodGenerator
22
{
23
    /**
24
     * @throws \Zend\Code\Generator\Exception\InvalidArgumentException
25
     */
26 4
    public static function generateMethod(ReflectionClass $originalClass, PropertyGenerator $valueHolder) : self
27
    {
28 4
        $originalConstructor = self::getConstructor($originalClass);
29
30
        /* @var $constructor Constructor */
31 4
        $constructor = $originalConstructor
32 1
            ? self::fromReflection($originalConstructor)
33 4
            : new self('__construct');
34
35 4
        $constructor->setDocBlock('{@inheritDoc}');
36 4
        $constructor->setBody(
37
            'static $reflection;' . "\n\n"
38 4
            . 'if (! $this->' . $valueHolder->getName() . ') {' . "\n"
39 4
            . '    $reflection = $reflection ?: new \ReflectionClass('
40 4
            . var_export($originalClass->getName(), true)
41 4
            . ");\n"
42 4
            . '    $this->' . $valueHolder->getName() . ' = $reflection->newInstanceWithoutConstructor();' . "\n"
43 4
            . UnsetPropertiesGenerator::generateSnippet(Properties::fromReflectionClass($originalClass), 'this')
44 4
            . '}'
45 4
            . self::generateOriginalConstructorCall($originalClass, $valueHolder)
46
        );
47
48 4
        return $constructor;
49
    }
50
51 4
    private static function generateOriginalConstructorCall(
52
        ReflectionClass $class,
53
        PropertyGenerator $valueHolder
54
    ) : string {
55 4
        $originalConstructor = self::getConstructor($class);
56
57 4
        if (! $originalConstructor) {
58 3
            return '';
59
        }
60
61 1
        $constructor = self::fromReflection($originalConstructor);
62
63
        return "\n\n"
64 1
            . '$this->' . $valueHolder->getName() . '->' . $constructor->getName() . '('
65 1
            . implode(
66 1
                ', ',
67 1
                array_map(
68 1
                    function (ParameterGenerator $parameter) : string {
69 1
                        return ($parameter->getVariadic() ? '...' : '') . '$' . $parameter->getName();
70 1
                    },
71 1
                    $constructor->getParameters()
72
                )
73
            )
74 1
            . ');';
75
    }
76
77
    /**
78
     * @param ReflectionClass $class
79
     *
80
     * @return MethodReflection|null
81
     */
82 4
    private static function getConstructor(ReflectionClass $class)
83
    {
84 4
        $constructors = array_map(
85 4
            function (\ReflectionMethod $method) : MethodReflection {
86 1
                return new MethodReflection(
87 1
                    $method->getDeclaringClass()->getName(),
88 1
                    $method->getName()
89
                );
90 4
            },
91 4
            array_filter(
92 4
                $class->getMethods(),
93 4
                function (\ReflectionMethod $method) : bool {
94 1
                    return $method->isConstructor();
95 4
                }
96
            )
97
        );
98
99
        return reset($constructors) ?: null;
100
    }
101
}
102