Passed
Push — master ( 50749f...7b5f02 )
by Gerrit
12:36
created

CallDefinition::__sleep()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 2
cts 2
cp 1
rs 9.9666
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
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
21
final class CallDefinition implements CallDefinitionInterface
22
{
23
24
    /**
25
     * @var ContainerInterface
26
     */
27
    private $container;
28
29
    /**
30
     * @var string|null
31
     */
32
    private $objectReference;
33
34
    /**
35
     * @var string
36
     */
37
    private $routineName;
38
39
    /**
40
     * @var array<MappingInterface>
41
     */
42
    private $argumentMappings = array();
43
44
    /**
45
     * @var bool
46
     */
47
    private $isStaticCall;
48
49 13
    public function __construct(
50
        ContainerInterface $container,
51
        string $routineName,
52
        string $objectReference = null,
53
        array $argumentMappings = array(),
54
        bool $isStaticCall = false
55
    ) {
56 13
        $this->routineName = $routineName;
57 13
        $this->objectReference = $objectReference;
58 13
        $this->isStaticCall = $isStaticCall;
59 13
        $this->container = $container;
60
61 13
        foreach ($argumentMappings as $argumentMapping) {
62
            /** @var MappingInterface $argumentMapping */
63
64 13
            Assert::isInstanceOf($argumentMapping, MappingInterface::class);
65
66 13
            $this->argumentMappings[] = $argumentMapping;
67
        }
68 13
    }
69
70 1
    public function __sleep(): array
71
    {
72
        return [
73 1
            'objectReference',
74
            'routineName',
75
            'argumentMappings',
76
            'isStaticCall',
77
        ];
78
    }
79
80 7
    public function execute(
81
        HydrationContextInterface $context,
82
        array $dataFromAdditionalColumns
83
    ) {
84
        /** @var mixed $result */
85 7
        $result = null;
0 ignored issues
show
Unused Code introduced by
$result 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...
86
87
        /** @var null|object|string $callee */
88 7
        $callee = $this->resolveCallee((string)$this->objectReference, $context);
89
90 7
        if ($this->isStaticCall && is_object($callee)) {
91
            $callee = get_class($callee);
92
        }
93
94
        /** @var array<mixed> $arguments */
95 7
        $arguments = $this->resolveArguments(
96 7
            $context,
97
            $dataFromAdditionalColumns
98
        );
99
100 7
        if (is_null($callee) && !empty($this->objectReference)) {
101
            $result = null;
102
103 7
        } elseif (is_null($callee)) {
104 1
            $result = call_user_func_array($this->routineName, $arguments);
105
106 6
        } elseif (is_string($callee)) {
107 1
            $result = call_user_func_array("{$callee}::{$this->routineName}", $arguments);
108
109
        } else {
110 5
            $result = call_user_func_array([$callee, $this->routineName], $arguments);
111
        }
112
113 7
        return $result;
114
    }
115
116 1
    public function getObjectReference(): ?string
117
    {
118 1
        return $this->objectReference;
119
    }
120
121 1
    public function getRoutineName(): string
122
    {
123 1
        return $this->routineName;
124
    }
125
126 1
    public function getArgumentMappings(): array
127
    {
128 1
        return $this->argumentMappings;
129
    }
130
131 1
    public function isStaticCall(): bool
132
    {
133 1
        return $this->isStaticCall;
134
    }
135
136
    /**
137
     * (This return type should be nullable, but there seems to be a bug in current version psalm preventing it.)
138
     *
139
     * @return object|string|null
140
     */
141 7
    private function resolveCallee(
142
        string $objectReference,
143
        HydrationContextInterface $context
144
    ) {
145
        /** @var object|string $callee */
146 7
        $callee = null;
147
148 7
        if (!empty($objectReference)) {
149
            /** @var array<mixed> $hydrationStack */
150 6
            $hydrationStack = $context->getObjectHydrationStack();
151
152 6
            if ($objectReference[0] === '$') {
153 1
                $objectReference = substr($objectReference, 1);
154
            }
155
156 6
            if (in_array($objectReference, ['root', 'entity'])) {
157
                $callee = $context->getEntity();
158
159 6
            } elseif (in_array($objectReference, ['self', 'this'])) {
160 2
                $callee = $hydrationStack[count($hydrationStack) - 1];
161
162 4
            } elseif (in_array($objectReference, ['parent'])) {
163 1
                $callee = $hydrationStack[count($hydrationStack) - 2];
164
165 3
            } elseif ($objectReference[0] === '@') {
166
                /** @var string $serviceId */
167 2
                $serviceId = substr($objectReference, 1);
168
169 2
                $callee = $this->container->get($serviceId);
170
171 1
            } elseif (class_exists($objectReference)) {
172 1
                $callee = $objectReference;
173
174
            } elseif ($context->hasRegisteredValue($objectReference)) {
175
                $callee = $context->getRegisteredValue($objectReference);
176
            }
177
        }
178
179 7
        return $callee;
180
    }
181
182
    /**
183
     * @param array<scalar> $dataFromAdditionalColumns
184
     *
185
     * @return array<mixed>
186
     */
187 7
    private function resolveArguments(
188
        HydrationContextInterface $context,
189
        array $dataFromAdditionalColumns
190
    ): array {
191
        /** @var array<mixed> $arguments */
192 7
        $arguments = array();
193
194 7
        if (isset($dataFromAdditionalColumns[''])) {
195
            $arguments[] = $dataFromAdditionalColumns[''];
196
            unset($dataFromAdditionalColumns['']);
197
        }
198
199 7
        foreach ($this->argumentMappings as $argumentMapping) {
200
            /** @var MappingInterface $argumentMapping */
201
202 7
            $arguments[] = $argumentMapping->resolveValue(
203 7
                $context,
204
                $dataFromAdditionalColumns
0 ignored issues
show
Documentation introduced by
$dataFromAdditionalColumns is of type array<integer|string,int...|string|boolean|null"}>, but the function expects a array<integer,integer|do...e|string|boolean|array>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
205
            );
206
        }
207
208 7
        return $arguments;
209
    }
210
211 1
    public function wakeUpCall(ContainerInterface $container): void {
212 1
        $this->container = $container;
213 1
    }
214
}
215