Completed
Push — master ( 026476...5a8e15 )
by Gerrit
30:22
created

ArgumentCompiler::buildCallArguments()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 51
ccs 21
cts 21
cp 1
rs 8.1357
c 0
b 0
f 0
cc 7
nc 6
nop 3
crap 7

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 Psr\Container\ContainerInterface;
17
use ErrorException;
18
use ReflectionParameter;
19
use ReflectionType;
20
use ReflectionMethod;
21
use Symfony\Component\HttpFoundation\Request;
22
use Webmozart\Assert\Assert;
23
use Addiks\SymfonyGenerics\Services\EntityRepositoryInterface;
24
use ReflectionClass;
25
26
final class ArgumentCompiler implements ArgumentCompilerInterface
27
{
28
29
    /**
30
     * @var ContainerInterface
31
     */
32
    private $container;
33
34
    /**
35
     * @var EntityRepositoryInterface
36
     */
37
    private $entityRepository;
38
39 4
    public function __construct(
40
        ContainerInterface $container,
41
        EntityRepositoryInterface $entityRepository
42
    ) {
43 4
        $this->container = $container;
44 4
        $this->entityRepository = $entityRepository;
45 4
    }
46
47 2
    public function buildArguments(
48
        array $argumentsConfiguration,
49
        Request $request
50
    ): array {
51
        /** @var array<int, mixed> $routeArguments */
52 2
        $routeArguments = array();
53
54 2
        foreach ($argumentsConfiguration as $key => $argumentConfiguration) {
55
            /** @var array|string $argumentConfiguration */
56
57
            /** @var string|null $parameterTypeName */
58 2
            $parameterTypeName = null;
59
60 2
            if (isset($argumentConfiguration['entity-class'])) {
61
                $parameterTypeName = $argumentConfiguration['entity-class'];
62
            }
63
64
            /** @var mixed $argumentValue */
65 2
            $argumentValue = $this->resolveArgumentConfiguration(
66 2
                $argumentConfiguration,
67 2
                $request,
68 2
                $parameterTypeName
69
            );
70
71 2
            $routeArguments[$key] = $argumentValue;
72
        }
73
74 1
        return $routeArguments;
75
    }
76
77 3
    public function buildCallArguments(
78
        ReflectionMethod $methodReflection,
79
        array $argumentsConfiguration,
80
        Request $request
81
    ): array {
82
        /** @var array<int, mixed> $callArguments */
83 3
        $callArguments = array();
84
85 3
        foreach ($methodReflection->getParameters() as $index => $parameterReflection) {
86
            /** @var ReflectionParameter $parameterReflection */
87
88
            /** @var string $parameterName */
89 2
            $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...
90
91
            /** @var mixed $requestValue */
92 2
            $requestValue = $request->get($parameterName);
93
94 2
            if (isset($argumentsConfiguration[$parameterName])) {
95
                /** @var array|string $argumentConfiguration */
96 2
                $argumentConfiguration = $argumentsConfiguration[$parameterName];
97
98 2
                Assert::true(is_string($argumentConfiguration) || is_array($argumentConfiguration));
99
100
                /** @var string|null $parameterTypeName */
101 1
                $parameterTypeName = null;
102
103 1
                if ($parameterReflection->hasType()) {
104
                    /** @var ReflectionType|null $parameterType */
105 1
                    $parameterType = $parameterReflection->getType();
106
107 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...
108 1
                        $parameterTypeName = $parameterType->__toString();
109
                    }
110
                }
111
112
                /** @var mixed $argumentValue */
113 1
                $argumentValue = $this->resolveArgumentConfiguration(
114 1
                    $argumentConfiguration,
115 1
                    $request,
116 1
                    $parameterTypeName
117
                );
118
119 1
                $callArguments[$index] = $argumentValue;
120
121 1
            } elseif (!is_null($requestValue)) {
122 1
                $callArguments[$index] = $requestValue;
123
            }
124
        }
125
126 2
        return $callArguments;
127
    }
128
129
    /**
130
     * @param array|string $argumentConfiguration
131
     *
132
     * @return mixed
133
     */
134 3
    private function resolveArgumentConfiguration(
135
        $argumentConfiguration,
136
        Request $request,
137
        ?string $parameterTypeName
138
    ) {
139
        /** @var mixed $argumentValue */
140 3
        $argumentValue = null;
141
142 3
        if (is_array($argumentConfiguration)) {
143
            if (isset($argumentConfiguration['id'])) {
144
                $argumentValue = $this->container->get($argumentConfiguration['id']);
145
            }
146
147
        } else {
148 3
            if (is_int(strpos($argumentConfiguration, '::'))) {
149 2
                [$factoryClass, $factoryMethod] = explode('::', $argumentConfiguration);
0 ignored issues
show
Bug introduced by
The variable $factoryClass does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $factoryMethod does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
150
151 2
                if (!empty($factoryClass)) {
152 2
                    if ($factoryClass[0] == '@') {
153
                        /** @var string $factoryServiceId */
154 2
                        $factoryServiceId = substr($factoryClass, 1);
155
156
                        /** @var object|null $factoryObject */
157 2
                        $factoryObject = $this->container->get($factoryServiceId);
158
159 2
                        Assert::methodExists($factoryObject, $factoryMethod, sprintf(
160 2
                            "Did not find service with id '%s' that has a method '%s'!",
161 2
                            $factoryServiceId,
162 2
                            $factoryMethod
163
                        ));
164
165 1
                        $factoryReflection = new ReflectionClass($factoryObject);
166
167
                        /** @var ReflectionMethod $methodReflection */
168 1
                        $methodReflection = $factoryReflection->getMethod($factoryMethod);
169
170 1
                        $callArguments = $this->buildCallArguments(
171 1
                            $methodReflection,
172 1
                            [], # TODO
173 1
                            $request
174
                        );
175
176
                        # Create by factory-service-object
177 1
                        $argumentValue = call_user_func_array([$factoryObject, $factoryMethod], $callArguments);
178
179
                    } else {
180
                        # Create by static factory-method of other class
181 1
                        $argumentValue = call_user_func_array($argumentConfiguration, []);
182
                    }
183
                }
184
185 3
            } elseif ($argumentConfiguration[0] == '$') {
186 3
                $argumentValue = $request->get(substr($argumentConfiguration, 1));
187
188 1
            } elseif ($argumentConfiguration[0] == '@') {
189 1
                $argumentValue = $this->container->get(substr($argumentConfiguration, 1));
190
            }
191
        }
192
193 3
        if (!empty($parameterTypeName)) {
194 1
            if (class_exists($parameterTypeName)) {
195 1
                $argumentValue = $this->entityRepository->findEntity($parameterTypeName, $argumentValue);
196
                # TODO: error handling "not an entty", "entity not found", ...
197
            }
198
        }
199
200 3
        return $argumentValue;
201
    }
202
203
}
204