Completed
Pull Request — master (#7)
by
unknown
04:26
created

areAllMethodArgumentsRequired()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 2
nop 2
crap 2
1
<?php
2
3
/*
4
 * This file is part of Symplify
5
 * Copyright (c) 2016 Tomas Votruba (http://tomasvotruba.cz).
6
 */
7
8
namespace Symplify\DefaultAutowire\DependencyInjection\Definition;
9
10
use ReflectionClass;
11
use ReflectionMethod;
12
use Symfony\Component\DependencyInjection\ContainerBuilder;
13
use Symfony\Component\DependencyInjection\Definition;
14
use Symfony\Component\DependencyInjection\Reference;
15
16
final class DefinitionAnalyzer
17
{
18
    /**
19
     * @var DefinitionValidator
20
     */
21
    private $definitionValidator;
22
23 11
    public function __construct(DefinitionValidator $definitionValidator)
24
    {
25 11
        $this->definitionValidator = $definitionValidator;
26 11
    }
27
28 11
    public function shouldDefinitionBeAutowired(ContainerBuilder $containerBuilder, Definition $definition) : bool
29
    {
30 11
        if (!$this->definitionValidator->validate($definition)) {
31 1
            return false;
32
        }
33
34 11
        $isFactory = $definition->getFactory() !== null;
35
36 11
        if ($isFactory) {
37 7
            return $this->shouldFactoryBuiltDefinitionBeAutowired($containerBuilder, $definition);
38
        } else {
39 5
            return $this->shouldClassDefinitionBeAutowired($definition);
40
        }
41
    }
42
43
    /**
44
     * @param ContainerBuilder $containerBuilder
45
     * @param Definition $definition
46
     *
47
     * @return bool
48
     */
49 7
    private function shouldFactoryBuiltDefinitionBeAutowired(
50
        ContainerBuilder $containerBuilder,
51
        Definition $definition
52
    ) : bool {
53 7
        $factory = $definition->getFactory();
54
55
        // functions specified as string are not supported
56 7
        if (is_string($factory)) {
57
            return false;
58
        }
59
60 7
        list($class, $method) = $factory;
61 7
        if ($class instanceof Reference) {
62 4
            $factoryClassDefinition = $containerBuilder->getDefinition($class);
63 4
            $class = $factoryClassDefinition->getClass();
64
        }
65
66 7
        $factoryMethodReflection = new ReflectionMethod($class, $method);
67
68 7
        if (!$this->hasMethodArguments($factoryMethodReflection)) {
69 2
            return false;
70
        }
71
72 5
        if ($this->areAllMethodArgumentsRequired($definition, $factoryMethodReflection)) {
73 3
            return false;
74
        }
75
76 3
        if (!$this->haveMissingArgumentsTypehints($definition, $factoryMethodReflection)) {
77
            return false;
78
        }
79
80 3
        return true;
81
    }
82
83 5
    private function shouldClassDefinitionBeAutowired(Definition $definition) : bool
84
    {
85 5
        $classReflection = new ReflectionClass($definition->getClass());
86 5
        if (!$classReflection->hasMethod('__construct')
87 5
            || !$this->hasMethodArguments($classReflection->getConstructor())
88
        ) {
89 2
            return false;
90
        }
91
92 4
        $constructorReflection = $classReflection->getConstructor();
93 4
        if ($this->areAllMethodArgumentsRequired($definition, $constructorReflection)) {
94 2
            return false;
95
        }
96
97 3
        if (!$this->haveMissingArgumentsTypehints($definition, $constructorReflection)) {
98 1
            return false;
99
        }
100
101 3
        return true;
102
    }
103
104 11
    private function hasMethodArguments(ReflectionMethod $methodReflection) : bool
105
    {
106 11
        return $methodReflection->getNumberOfParameters() !== 0;
107
    }
108
109 8
    private function areAllMethodArgumentsRequired(
110
        Definition $definition,
111
        ReflectionMethod $constructorReflection
112
    ) : bool {
113 8
        $constructorArgumentsCount = count($definition->getArguments());
114 8
        $constructorRequiredArgumentsCount = $constructorReflection->getNumberOfRequiredParameters();
115
116 8
        if ($constructorArgumentsCount === $constructorRequiredArgumentsCount) {
117 4
            return true;
118
        }
119
120 5
        return false;
121
    }
122
123 5
    private function haveMissingArgumentsTypehints(
124
        Definition $definition,
125
        ReflectionMethod $constructorReflection
126
    ) : bool {
127 5
        $arguments = $definition->getArguments();
128 5
        if (!count($arguments)) {
129 2
            return true;
130
        }
131
132 4
        $i = 0;
133 4
        foreach ($constructorReflection->getParameters() as $parameterReflection) {
134 4
            if (!isset($arguments[$i])) {
135 4
                if ($parameterReflection->isDefaultValueAvailable()) {
136 1
                    ++$i;
137 1
                    continue;
138
                }
139
140 3
                if (null !== $parameterReflection->getType()) {
141 3
                    return true;
142
                }
143
            }
144
145 4
            ++$i;
146
        }
147
148 1
        return false;
149
    }
150
}
151