FactoryDefinition::buildFactoryCode()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 18
nc 3
nop 1
dl 0
loc 28
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
4
namespace TheCodingMachine\Funky;
5
6
use Psr\Container\ContainerInterface;
7
use ReflectionMethod;
8
use TheCodingMachine\Funky\Annotations\Factory;
9
use TheCodingMachine\Funky\Injections\Injection;
10
11
class FactoryDefinition extends AbstractDefinition
12
{
13
    private $aliases;
14
15
    public function __construct(ReflectionMethod $reflectionMethod, Factory $annotation)
16
    {
17
        if (!$reflectionMethod->isPublic()) {
18
            throw BadModifierException::mustBePublic($reflectionMethod, '@Factory');
19
        }
20
        if (!$reflectionMethod->isStatic()) {
21
            throw BadModifierException::mustBeStatic($reflectionMethod, '@Factory');
22
        }
23
24
        if ($annotation->isFromMethodName()) {
25
            $this->name = $reflectionMethod->getName();
26
        } elseif ($annotation->isFromType()) {
27
            $returnType = $reflectionMethod->getReturnType();
28
            if ($returnType === null) {
29
                throw UnknownTypeException::create($reflectionMethod);
30
            }
31
            $this->name = (string) $returnType;
32
        } else {
33
            $this->name = (string) $annotation->getName();
34
        }
35
36
        $this->tags = $annotation->getTags();
37
38
        parent::__construct($reflectionMethod);
39
        $this->aliases = $annotation->getAliases();
40
    }
41
42
    /**
43
     * Returns true if the signature of the reflection method is compatible with container-interop/service-provider
44
     * factories.
45
     */
46
    public function isPsrFactory(): bool
47
    {
48
        $numberOfParameters = $this->reflectionMethod->getNumberOfParameters();
49
        if ($numberOfParameters > 1) {
50
            return false;
51
        }
52
        if ($numberOfParameters === 0) {
53
            return true;
54
        }
55
        $parameter = $this->reflectionMethod->getParameters()[0];
56
        return $parameter !== null && (string) $parameter->getType() === ContainerInterface::class;
57
    }
58
59
    public function buildFactoryCode(string $functionName) : string
60
    {
61
        $returnTypeCode = '';
62
        $returnType = $this->reflectionMethod->getReturnType();
63
        if ($returnType) {
64
            if ($returnType->isBuiltin()) {
65
                $returnTypeCode = ': '.$this->reflectionMethod->getReturnType();
66
            } else {
67
                $returnTypeCode = ': \\'.$this->reflectionMethod->getReturnType();
68
            }
69
        }
70
71
        return sprintf(
72
            <<<EOF
73
    public static function %s(ContainerInterface \$container)%s
74
    {
75
        return %s::%s(%s);
76
    }
77
    
78
EOF
79
            ,
80
            $functionName,
81
            $returnTypeCode,
82
            '\\'.$this->reflectionMethod->getDeclaringClass()->getName(),
83
            $this->reflectionMethod->getName(),
84
            implode(', ', array_map(function (Injection $injection) {
85
                return $injection->getCode();
86
            }, $this->getInjections()))
87
        );
88
    }
89
90
    /**
91
     * Returns a list of services to be injected.
92
     *
93
     * @return Injection[]
94
     */
95
    private function getInjections(): array
96
    {
97
        return array_map([$this, 'mapParameterToInjection'], $this->getReflectionMethod()->getParameters());
98
    }
99
100
    /**
101
     * @return string[]
102
     */
103
    public function getAliases(): array
104
    {
105
        return $this->aliases;
106
    }
107
}
108