Passed
Push — master ( d684ef...9fb777 )
by Gerrit
01:56
created

NewArgumentCompiler   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 150
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 5
dl 0
loc 150
ccs 56
cts 56
cp 1
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A buildArguments() 0 21 3
C buildCallArguments() 0 63 10
A resolveArgumentConfiguration() 0 29 3
1
<?php
2
/**
3
 * Copyright (C) 2018 Gerrit Addiks.
4
 * This package (including this file) was released under the terms of the GPL-3.0.
5
 * You should have received a copy of the GNU General Public License along with this program.
6
 * If not, see <http://www.gnu.org/licenses/> or send me a mail so i can send you a copy.
7
 *
8
 * @license GPL-3.0
9
 *
10
 * @author Gerrit Addiks <[email protected]>
11
 */
12
13
namespace Addiks\SymfonyGenerics\Services;
14
15
use Addiks\SymfonyGenerics\Services\ArgumentCompilerInterface;
16
use Addiks\SymfonyGenerics\Arguments\ArgumentFactory\ArgumentFactory;
17
use Addiks\SymfonyGenerics\Arguments\Argument;
18
use Symfony\Component\HttpFoundation\Request;
19
use Webmozart\Assert\Assert;
20
use ErrorException;
21
use ReflectionType;
22
use ReflectionFunctionAbstract;
23
use ReflectionParameter;
24
use ReflectionException;
25
use Symfony\Component\HttpFoundation\RequestStack;
26
use Addiks\SymfonyGenerics\Arguments\ArgumentContextInterface;
27
use InvalidArgumentException;
28
29
final class NewArgumentCompiler implements ArgumentCompilerInterface
30
{
31
32
    /**
33
     * @var ArgumentFactory
34
     */
35
    private $argumentFactory;
36
37
    /**
38
     * @var RequestStack
39
     */
40
    private $requestStack;
41
42
    /**
43
     * @var ArgumentContextInterface
44
     */
45
    private $argumentContext;
46
47 10
    public function __construct(
48
        ArgumentFactory $argumentFactory,
49
        RequestStack $requestStack,
50
        ArgumentContextInterface $argumentContext
51
    ) {
52 10
        $this->argumentFactory = $argumentFactory;
53 10
        $this->requestStack = $requestStack;
54 10
        $this->argumentContext = $argumentContext;
55 10
    }
56
57 6
    public function buildArguments(
58
        array $argumentsConfiguration,
59
        Request $request,
60
        array $additionalData = array()
61
    ): array {
62
        /** @var array $argumentValues */
63 6
        $argumentValues = array();
64
65 6
        $this->argumentContext->clear();
66 6
        foreach ($additionalData as $key => $value) {
67 3
            $this->argumentContext->set($key, $value);
68
        }
69
70 6
        foreach ($argumentsConfiguration as $key => $argumentConfiguration) {
71
            /** @var array|string $argumentConfiguration */
72
73 5
            $argumentValues[$key] = $this->resolveArgumentConfiguration($argumentConfiguration);
74
        }
75
76 3
        return $argumentValues;
77
    }
78
79 4
    public function buildCallArguments(
80
        ReflectionFunctionAbstract $routineReflection,
81
        array $argumentsConfiguration,
82
        Request $request,
83
        array $predefinedArguments = array(),
84
        array $additionalData = array()
85
    ): array {
86
        /** @var array<int, mixed> $callArguments */
87 4
        $callArguments = array();
88
89 4
        $this->argumentContext->clear();
90 4
        foreach ($additionalData as $key => $value) {
91 3
            $this->argumentContext->set($key, $value);
92
        }
93
94 4
        foreach ($routineReflection->getParameters() as $index => $parameterReflection) {
95
            /** @var ReflectionParameter $parameterReflection */
96
97 3
            if (isset($predefinedArguments[$index])) {
98 2
                $callArguments[$index] = $predefinedArguments[$index];
99 2
                continue;
100
            }
101
102
            /** @var string $parameterName */
103 3
            $parameterName = $parameterReflection->getName();
0 ignored issues
show
Bug introduced by
Consider using $parameterReflection->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
104
105
            /** @var string|null $parameterTypeName */
106 3
            $parameterTypeName = null;
107
108 3
            if ($parameterReflection->hasType()) {
109
                /** @var ReflectionType|null $parameterType */
110 1
                $parameterType = $parameterReflection->getType();
111
112 1
                if ($parameterType instanceof ReflectionType) {
0 ignored issues
show
Bug introduced by
The class ReflectionType does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
113 1
                    $parameterTypeName = $parameterType->__toString();
114
                }
115
            }
116
117 3
            if (isset($argumentsConfiguration[$parameterName])) {
118 1
                $callArguments[$index] = $this->resolveArgumentConfiguration($argumentsConfiguration[$parameterName]);
119
120 2
            } elseif (isset($argumentsConfiguration[$index])) {
121 1
                $callArguments[$index] = $this->resolveArgumentConfiguration($argumentsConfiguration[$index]);
122
123 2
            } elseif ($parameterTypeName === Request::class) {
124 1
                $callArguments[$index] = $this->requestStack->getCurrentRequest();
125
126
            } else {
127
                try {
128 1
                    $callArguments[$index] = $parameterReflection->getDefaultValue();
129
130 1
                } catch (ReflectionException $exception) {
131 1
                    throw new InvalidArgumentException(sprintf(
132 1
                        "Missing argument '%s' for the call to '%s'!",
133 1
                        $parameterName,
134 3
                        $routineReflection->getName()
135
                    ));
136
                }
137
            }
138
        }
139
140 3
        return $callArguments;
141
    }
142
143
    /**
144
     * @param array|string $argumentConfiguration
145
     *
146
     * @return mixed
147
     */
148 7
    private function resolveArgumentConfiguration($argumentConfiguration)
149
    {
150 7
        Assert::true(
151 7
            is_array($argumentConfiguration) || is_string($argumentConfiguration),
152 7
            "Arguments must be defined as string or array!"
153
        );
154
155
        /** @var Argument|null $argument */
156 6
        $argument = null;
0 ignored issues
show
Unused Code introduced by
$argument is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
157
158 6
        if (is_array($argumentConfiguration)) {
159 2
            Assert::true($this->argumentFactory->understandsArray($argumentConfiguration), sprintf(
160 2
                "Argument '%s' could not be understood!",
161 2
                preg_replace("/\s+/is", "", var_export($argumentConfiguration, true))
162
            ));
163
164 1
            $argument = $this->argumentFactory->createArgumentFromArray($argumentConfiguration);
165
166
        } else {
167 4
            Assert::true($this->argumentFactory->understandsString($argumentConfiguration), sprintf(
168 4
                "Argument '%s' could not be understood!",
169 4
                $argumentConfiguration
170
            ));
171
172 3
            $argument = $this->argumentFactory->createArgumentFromString($argumentConfiguration);
173
        }
174
175 4
        return $argument->resolve();
176
    }
177
178
}
179