Passed
Push — master ( 356755...14835f )
by Gerrit
04:25
created

CallDefinitionExecuter::executeCallDefinition()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 46
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 7.049

Importance

Changes 0
Metric Value
dl 0
loc 46
ccs 18
cts 20
cp 0.9
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 24
nc 8
nop 3
crap 7.049
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\ValueResolver;
14
15
use Addiks\RDMBundle\ValueResolver\CallDefinitionExecuterInterface;
16
use Addiks\RDMBundle\Mapping\CallDefinitionInterface;
17
use Addiks\RDMBundle\Mapping\MappingInterface;
18
use Symfony\Component\DependencyInjection\ContainerInterface;
19
use Addiks\RDMBundle\ValueResolver\ValueResolverInterface;
20
use Addiks\RDMBundle\Hydration\HydrationContextInterface;
21
use Addiks\RDMBundle\Exception\InvalidMappingException;
22
23
final class CallDefinitionExecuter implements CallDefinitionExecuterInterface
24
{
25
26
    /**
27
     * @var ContainerInterface
28
     */
29
    private $container;
30
31
    /**
32
     * @var ValueResolverInterface
33
     */
34
    private $argumentResolver;
35
36 10
    public function __construct(
37
        ContainerInterface $container,
38
        ValueResolverInterface $argumentResolver
39
    ) {
40 10
        $this->container = $container;
41 10
        $this->argumentResolver = $argumentResolver;
42 10
    }
43
44 6
    public function executeCallDefinition(
45
        CallDefinitionInterface $callDefinition,
46
        HydrationContextInterface $context,
47
        array $dataFromAdditionalColumns
48
    ) {
49
        /** @var mixed $result */
50 6
        $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...
51
52
        /** @var string $objectReference */
53 6
        $objectReference = $callDefinition->getObjectReference();
54
55
        /** @var string $routineName */
56 6
        $routineName = $callDefinition->getRoutineName();
57
58
        /** @var array<MappingInterface> $argumentMappings */
59 6
        $argumentMappings = $callDefinition->getArgumentMappings();
60
61
        /** @var null|object|string $callee */
62 6
        $callee = $this->resolveCallee($objectReference, $context);
63
64 6
        if ($callDefinition->isStaticCall() && is_object($callee)) {
65
            $callee = get_class($callee);
66
        }
67
68
        /** @var array<mixed> $arguments */
69 6
        $arguments = $this->resolveArguments(
70 6
            $argumentMappings,
71 6
            $context,
72 6
            $dataFromAdditionalColumns
73
        );
74
75 6
        if (is_null($callee) && !empty($objectReference)) {
76
            $result = null;
77
78 6
        } elseif (is_null($callee)) {
79 1
            $result = call_user_func_array($routineName, $arguments);
80
81 5
        } elseif (is_string($callee)) {
82 1
            $result = call_user_func_array("{$callee}::{$routineName}", $arguments);
83
84
        } else {
85 4
            $result = call_user_func_array([$callee, $routineName], $arguments);
86
        }
87
88 6
        return $result;
89
    }
90
91
    /**
92
     * (This return type should be nullable, but there seems to be a bug in current version psalm preventing it.)
93
     *
94
     * @return object|string
95
     */
96 6
    private function resolveCallee(
97
        string $objectReference,
98
        HydrationContextInterface $context
99
    ) {
100
        /** @var object|string $callee */
101 6
        $callee = null;
102
103 6
        if (!empty($objectReference)) {
104
            /** @var array<mixed> $hydrationStack */
105 5
            $hydrationStack = $context->getObjectHydrationStack();
106
107 5
            if ($objectReference[0] === '$') {
108 1
                $objectReference = substr($objectReference, 1);
109
            }
110
111 5
            if (in_array($objectReference, ['root', 'entity'])) {
112
                $callee = $context->getEntity();
113
114 5
            } elseif (in_array($objectReference, ['self', 'this'])) {
115 2
                $callee = $hydrationStack[count($hydrationStack)-1];
116
117 3
            } elseif (in_array($objectReference, ['parent'])) {
118 1
                $callee = $hydrationStack[count($hydrationStack)-2];
119
120 2
            } elseif ($objectReference[0] === '@') {
121
                /** @var string $serviceId */
122 1
                $serviceId = substr($objectReference, 1);
123
124 1
                $callee = $this->container->get($serviceId);
125
126 1
            } elseif (class_exists($objectReference)) {
127 1
                $callee = $objectReference;
128
129
            } elseif ($context->hasRegisteredValue($objectReference)) {
130
                $callee = $context->getRegisteredValue($objectReference);
131
            }
132
        }
133
134 6
        return $callee;
135
    }
136
137
    /**
138
     * @param array<MappingInterface> $argumentMappings
139
     * @param array<scalar>           $dataFromAdditionalColumns
140
     *
141
     * @return array<mixed>
142
     */
143 6
    private function resolveArguments(
144
        array $argumentMappings,
145
        HydrationContextInterface $context,
146
        array $dataFromAdditionalColumns
147
    ): array {
148
        /** @var array<mixed> $arguments */
149 6
        $arguments = array();
150
151 6
        if (isset($dataFromAdditionalColumns[''])) {
152
            $arguments[] = $dataFromAdditionalColumns[''];
153
            unset($dataFromAdditionalColumns['']);
154
        }
155
156 6
        foreach ($argumentMappings as $argumentMapping) {
157
            /** @var MappingInterface $argumentMapping */
158
159 2
            $arguments[] = $this->argumentResolver->resolveValue(
160 2
                $argumentMapping,
161 2
                $context,
162 2
                $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|double|string|boolean>.

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...
163
            );
164
        }
165
166 6
        return $arguments;
167
    }
168
169
}
170