Passed
Push — master ( 064bed...d815ea )
by Gerrit
04:18
created

CallDefinition::execute()   C

Complexity

Conditions 13
Paths 104

Size

Total Lines 63
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 44.5287

Importance

Changes 0
Metric Value
cc 13
eloc 34
c 0
b 0
f 0
nc 104
nop 2
dl 0
loc 63
ccs 12
cts 28
cp 0.4286
crap 44.5287
rs 6.5833

How to fix   Long Method    Complexity   

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\RDMBundle\Mapping;
14
15
use Addiks\RDMBundle\Mapping\CallDefinitionInterface;
16
use Addiks\RDMBundle\Mapping\MappingInterface;
17
use Webmozart\Assert\Assert;
18
use Addiks\RDMBundle\Hydration\HydrationContextInterface;
19
use Symfony\Component\DependencyInjection\ContainerInterface;
20
use Doctrine\ORM\Exception\ORMException;
21
use Doctrine\Common\Util\ClassUtils;
22
use ArgumentCountError;
23
24
final class CallDefinition implements CallDefinitionInterface
25
{
26
27
    /**
28
     * @var ContainerInterface
29
     */
30
    private $container;
31
32
    /**
33
     * @var string|null
34
     */
35
    private $objectReference;
36
37
    /**
38
     * @var string
39
     */
40
    private $routineName;
41
42
    /**
43
     * @var array<MappingInterface>
44
     */
45
    private $argumentMappings = array();
46
47
    /**
48
     * @var bool
49
     */
50
    private $isStaticCall;
51
52
    /**
53
     * @var string
54
     */
55
    private $origin;
56
57 13
    public function __construct(
58
        ContainerInterface $container,
59
        string $routineName,
60
        string $objectReference = null,
61
        array $argumentMappings = array(),
62
        bool $isStaticCall = false,
63
        string $origin = "unknown"
64
    ) {
65 13
        $this->routineName = $routineName;
66 13
        $this->objectReference = $objectReference;
67 13
        $this->isStaticCall = $isStaticCall;
68 13
        $this->container = $container;
69 13
        $this->origin = $origin;
70
71 13
        foreach ($argumentMappings as $argumentMapping) {
72
            /** @var MappingInterface $argumentMapping */
73
74 13
            Assert::isInstanceOf($argumentMapping, MappingInterface::class);
75
76 13
            $this->argumentMappings[] = $argumentMapping;
77
        }
78
    }
79
80 1
    public function __sleep(): array
81
    {
82
        return [
83 1
            'objectReference',
84
            'routineName',
85
            'argumentMappings',
86
            'isStaticCall',
87
            'origin',
88
        ];
89
    }
90
91 7
    public function execute(
92
        HydrationContextInterface $context,
93
        array $dataFromAdditionalColumns
94
    ) {
95
        /** @var mixed $result */
96 7
        $result = null;
97
98
        /** @var null|object|string $callee */
99 7
        $callee = $this->resolveCallee((string)$this->objectReference, $context);
100
101 7
        if ($this->isStaticCall && is_object($callee)) {
102
            $callee = get_class($callee);
103
        }
104
105
        /** @var array<mixed> $arguments */
106 7
        $arguments = $this->resolveArguments(
107
            $context,
108
            $dataFromAdditionalColumns
109
        );
110
111
        try {
112 7
            if (is_null($callee) && !empty($this->objectReference)) {
113
                $result = null;
114
115 7
            } elseif (is_null($callee)) {
116 1
                $result = call_user_func_array($this->routineName, $arguments);
117
118 6
            } elseif (is_string($callee)) {
119 1
                $result = call_user_func_array("{$callee}::{$this->routineName}", $arguments);
120
121
            } else {
122 7
                $result = call_user_func_array([$callee, $this->routineName], $arguments);
123
            }
124
125
        } catch (ArgumentCountError $exception) {
126
            /** @var string $calleeDescription */
127
            $calleeDescription = "";
128
129
            if (is_object($callee)) {
130
                $calleeDescription = get_class($callee);
131
132
                if (class_exists(ClassUtils::class)) {
133
                    $calleeDescription = ClassUtils::getRealClass($calleeDescription);
134
                }
135
136
            } elseif (is_string($callee)) {
137
                $calleeDescription = $callee;
138
            }
139
140
            if (!empty($calleeDescription)) {
141
                $calleeDescription .= $this->isStaticCall ?'::' :'->';
142
            }
143
144
            throw new ORMException(sprintf(
145
                "Wrong number of arguments passed to routine '%s%s' in %s: %s",
146
                $calleeDescription,
147
                $this->routineName,
148
                $this->origin,
149
                $exception->getMessage()
150
            ), 0, $exception);
151
        }
152
153 7
        return $result;
154
    }
155
156 1
    public function getObjectReference(): ?string
157
    {
158 1
        return $this->objectReference;
159
    }
160
161 1
    public function getRoutineName(): string
162
    {
163 1
        return $this->routineName;
164
    }
165
166 1
    public function getArgumentMappings(): array
167
    {
168 1
        return $this->argumentMappings;
169
    }
170
171 1
    public function isStaticCall(): bool
172
    {
173 1
        return $this->isStaticCall;
174
    }
175
176
    /**
177
     * (This return type should be nullable, but there seems to be a bug in current version psalm preventing it.)
178
     *
179
     * @return object|string|null
180
     */
181 7
    private function resolveCallee(
182
        string $objectReference,
183
        HydrationContextInterface $context
184
    ) {
185
        /** @var object|string $callee */
186 7
        $callee = null;
187
188 7
        if (!empty($objectReference)) {
189
            /** @var array<mixed> $hydrationStack */
190 6
            $hydrationStack = $context->getObjectHydrationStack();
191
192 6
            if ($objectReference[0] === '$') {
193 1
                $objectReference = substr($objectReference, 1);
194
            }
195
196 6
            if (in_array($objectReference, ['root', 'entity'])) {
197
                $callee = $context->getEntity();
198
199 6
            } elseif (in_array($objectReference, ['self', 'this'])) {
200 2
                $callee = $hydrationStack[count($hydrationStack) - 1];
201
202 4
            } elseif (in_array($objectReference, ['parent'])) {
203 1
                $callee = $hydrationStack[count($hydrationStack) - 2];
204
205 3
            } elseif ($objectReference[0] === '@') {
206
                /** @var string $serviceId */
207 2
                $serviceId = substr($objectReference, 1);
208
209 2
                $callee = $this->container->get($serviceId);
210
211 1
            } elseif (class_exists($objectReference)) {
212 1
                $callee = $objectReference;
213
214
            } elseif ($context->hasRegisteredValue($objectReference)) {
215
                $callee = $context->getRegisteredValue($objectReference);
216
            }
217
        }
218
219 7
        return $callee;
220
    }
221
222
    /**
223
     * @param array<scalar> $dataFromAdditionalColumns
224
     *
225
     * @return array<mixed>
226
     */
227 7
    private function resolveArguments(
228
        HydrationContextInterface $context,
229
        array $dataFromAdditionalColumns
230
    ): array {
231
        /** @var array<mixed> $arguments */
232 7
        $arguments = array();
233
234 7
        if (array_key_exists('', $dataFromAdditionalColumns)) {
235
            $arguments[] = $dataFromAdditionalColumns[''];
236
            unset($dataFromAdditionalColumns['']);
237
        }
238
239 7
        foreach ($this->argumentMappings as $argumentMapping) {
240
            /** @var MappingInterface $argumentMapping */
241
242 7
            $arguments[] = $argumentMapping->resolveValue(
243
                $context,
244
                $dataFromAdditionalColumns
245
            );
246
        }
247
248 7
        return $arguments;
249
    }
250
251 1
    public function wakeUpCall(ContainerInterface $container): void {
252 1
        $this->container = $container;
253
    }
254
}
255