Passed
Branch next (ee2197)
by Bas
02:37
created

NormalizesExpressions::normalizeArgument()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 4
eloc 7
c 1
b 0
f 1
nc 4
nop 2
dl 0
loc 17
ccs 8
cts 8
cp 1
crap 4
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LaravelFreelancerNL\FluentAQL\Traits;
6
7
use LaravelFreelancerNL\FluentAQL\Exceptions\ExpressionTypeException;
8
use LaravelFreelancerNL\FluentAQL\Expressions\Expression;
9
use LaravelFreelancerNL\FluentAQL\Expressions\ListExpression;
10
use LaravelFreelancerNL\FluentAQL\Expressions\NullExpression;
11
use LaravelFreelancerNL\FluentAQL\Expressions\ObjectExpression;
12
use LaravelFreelancerNL\FluentAQL\Expressions\PredicateExpression;
13
use LaravelFreelancerNL\FluentAQL\Expressions\QueryExpression;
14
use LaravelFreelancerNL\FluentAQL\Expressions\StringExpression;
15
use LaravelFreelancerNL\FluentAQL\QueryBuilder;
16
17
trait NormalizesExpressions
18
{
19
20
    abstract public function bind(mixed $data, string $to = null);
21
22
    /**
23
     * @param null|string[] $allowedExpressionTypes
24
     * @throws ExpressionTypeException
25
     */
26 54
    public function normalizeArgument(
27
        mixed $argument,
28
        array|string $allowedExpressionTypes = null
29
    ): Expression {
30 54
        if ($argument instanceof Expression) {
31 32
            return $argument;
32
        }
33
34 53
        if (is_scalar($argument)) {
35 53
            return $this->normalizeScalar($argument, $allowedExpressionTypes);
36
        }
37
38 13
        if (is_null($argument)) {
39 2
            return new NullExpression();
40
        }
41
42 13
        return $this->normalizeCompound($argument, $allowedExpressionTypes);
43
    }
44
45
    /**
46
     * @param array<mixed>|string|int|float|bool|null $argument
47
     * @param array<string>|string|null  $allowedExpressionTypes
48
     * @throws ExpressionTypeException
49
     */
50 53
    protected function normalizeScalar(
51
        array|string|int|float|bool|null $argument,
0 ignored issues
show
Bug introduced by
The type LaravelFreelancerNL\FluentAQL\Traits\null was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
52
        null|array|string $allowedExpressionTypes = null
53
    ): Expression {
54 53
        $argumentType = $this->determineArgumentType($argument, $allowedExpressionTypes);
55
56 53
        return $this->createExpression($argument, $argumentType);
57
    }
58
59 53
    protected function createExpression(
60
        mixed $argument,
61
        string $argumentType
62
    ): Expression {
63 53
        $expressionType = $this->grammar->mapArgumentTypeToExpressionType($argumentType);
64 53
        if ($expressionType == 'Bind') {
65 15
            return $this->bind($argument);
66
        }
67 49
        if ($expressionType == 'CollectionBind') {
68 1
            return $this->bindCollection($argument);
0 ignored issues
show
Bug introduced by
It seems like bindCollection() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

68
            return $this->/** @scrutinizer ignore-call */ bindCollection($argument);
Loading history...
69
        }
70 49
        $expressionClass = '\LaravelFreelancerNL\FluentAQL\Expressions\\' . $expressionType . 'Expression';
71
72 49
        return new $expressionClass($argument);
73
    }
74
75
    /**
76
     * @param array<mixed>|object $argument
77
     * @param array<string>|string|null  $allowedExpressionTypes
78
     * @return Expression
79
     * @throws ExpressionTypeException
80
     */
81 13
    protected function normalizeCompound(
82
        array|object $argument,
83
        null|array|string $allowedExpressionTypes = null
84
    ): Expression {
85 13
        if (is_array($argument)) {
0 ignored issues
show
introduced by
The condition is_array($argument) is always true.
Loading history...
86 8
            return $this->normalizeArray($argument, $allowedExpressionTypes);
87
        }
88 9
        if (!is_iterable($argument)) {
89 9
            return $this->normalizeObject($argument, $allowedExpressionTypes);
90
        }
91
92
        return new ObjectExpression($this->normalizeIterable((array) $argument, $allowedExpressionTypes));
93
    }
94
95
    /**
96
     * @param array<mixed> $argument
97
     * @param array<string>|string|null $allowedExpressionTypes
98
     * @return array<mixed>|Expression
99
     * @throws ExpressionTypeException
100
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
101
     */
102 10
    protected function normalizeIterable(
103
        array $argument,
104
        null|array|string $allowedExpressionTypes = null
105
    ): array|Expression {
106 10
        foreach ($argument as $attribute => $value) {
107 10
            $argument[$attribute] = $this->normalizeArgument($value);
108
        }
109
110 10
        return $argument;
111
    }
112
113
    /**
114
     * @param array<mixed>|PredicateExpression $predicates
115
     * @return array<mixed>|PredicateExpression
116
     * @throws ExpressionTypeException
117
     */
118 14
    public function normalizePredicates(
119
        array|PredicateExpression $predicates
120
    ): array|PredicateExpression {
121 14
        if ($this->grammar->isPredicate($predicates)) {
122 14
            return $this->normalizePredicate($predicates);
123
        }
124
125 13
        $normalizedPredicates = [];
126 13
        if (is_iterable($predicates)) {
127 13
            foreach ($predicates as $predicate) {
128 13
                $normalizedPredicates[] = $this->normalizePredicates($predicate);
129
            }
130
        }
131
132 13
        return $normalizedPredicates;
133
    }
134
135
    /**
136
     * @param array<mixed>|PredicateExpression $predicate
137
     * @return PredicateExpression
138
     * @throws ExpressionTypeException
139
     */
140 14
    protected function normalizePredicate(array|PredicateExpression $predicate): PredicateExpression
141
    {
142 14
        if ($predicate instanceof PredicateExpression) {
0 ignored issues
show
introduced by
$predicate is never a sub-type of LaravelFreelancerNL\Flue...ons\PredicateExpression.
Loading history...
143 2
            return $predicate;
144
        }
145
146 14
        $leftOperand = $this->normalizeArgument($predicate[0]);
147
148 14
        $comparisonOperator = null;
149 14
        if (isset($predicate[1])) {
150 13
            $comparisonOperator = $predicate[1];
151
        }
152
153
154 14
        $rightOperand = null;
155 14
        if (isset($predicate[2])) {
156 12
            $rightOperand = $this->normalizeArgument($predicate[2]);
157
        }
158
159 14
        $logicalOperator = 'AND';
160 14
        if (isset($predicate[3]) && $this->grammar->isLogicalOperator($predicate[3])) {
161 6
            $logicalOperator = $predicate[3];
162
        }
163
164 14
        return new PredicateExpression(
165 14
            $leftOperand,
166
            $comparisonOperator,
167
            $rightOperand,
168
            $logicalOperator
169
        );
170
    }
171
172
    /**
173
     * Return the first matching expression type for the argument from the allowed types.
174
     *
175
     * @param array<string>|string|null  $allowedExpressionTypes
176
     * @throws ExpressionTypeException
177
     */
178 53
    protected function determineArgumentType(
179
        mixed $argument,
180
        null|array|string $allowedExpressionTypes = null
181
    ): string {
182 53
        if (is_string($allowedExpressionTypes)) {
0 ignored issues
show
introduced by
The condition is_string($allowedExpressionTypes) is always false.
Loading history...
183 27
            $allowedExpressionTypes = [$allowedExpressionTypes];
184
        }
185 53
        if ($allowedExpressionTypes == null) {
186 21
            $allowedExpressionTypes = $this->grammar->getAllowedExpressionTypes();
187
        }
188
189 53
        foreach ($allowedExpressionTypes as $allowedExpressionType) {
190 53
            $check = 'is' . $allowedExpressionType;
191 53
            if ($allowedExpressionType == 'Reference' || $allowedExpressionType == 'RegisteredVariable') {
192 33
                if ($this->grammar->$check($argument, $this->variables)) {
193 19
                    return $allowedExpressionType;
194
                }
195
            }
196
197 53
            if ($this->grammar->$check($argument)) {
198 53
                return $allowedExpressionType;
199
            }
200
        }
201
202 1
        throw new ExpressionTypeException(
203
            "This argument, 
204 1
            '{$argument}', does not match one of these expression types: "
205 1
                . implode(', ', $allowedExpressionTypes)
206 1
                . '.'
207
        );
208
    }
209
210
    /**
211
     * @param array<mixed> $argument
212
     * @param array<string>|string|null  $allowedExpressionTypes
213
     * @throws ExpressionTypeException
214
     */
215 8
    protected function normalizeArray(
216
        array $argument,
217
        null|array|string $allowedExpressionTypes = null
218
    ): Expression {
219 8
        if ($this->grammar->isAssociativeArray($argument)) {
220 6
            return new ObjectExpression($this->normalizeIterable($argument, $allowedExpressionTypes));
221
        }
222
223 3
        return new ListExpression($this->normalizeIterable($argument, $allowedExpressionTypes));
224
    }
225
226
    /**
227
     * @param array<string>|string|null $allowedExpressionTypes
228
     * @throws ExpressionTypeException
229
     */
230 9
    protected function normalizeObject(
231
        object $argument,
232
        null|array|string $allowedExpressionTypes = null
233
    ): Expression {
234 9
        if ($argument instanceof \DateTimeInterface) {
235 1
            return new StringExpression($argument->format(\DateTime::ATOM));
236
        }
237
238 8
        if ($argument instanceof QueryBuilder) {
239 5
            return new QueryExpression($argument);
240
        }
241
242 3
        return new ObjectExpression($this->normalizeIterable((array) $argument, $allowedExpressionTypes));
243
    }
244
}
245