Failed Conditions
Branch prepare-alpha (4a2a7f)
by Bas
02:41
created

NormalizesExpressions::normalizeArray()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
ccs 3
cts 4
cp 0.75
crap 2.0625
rs 10
c 1
b 0
f 1
1
<?php
2
3
namespace LaravelFreelancerNL\FluentAQL\Traits;
4
5
use LaravelFreelancerNL\FluentAQL\Exceptions\ExpressionTypeException;
6
use LaravelFreelancerNL\FluentAQL\Expressions\BindExpression;
7
use LaravelFreelancerNL\FluentAQL\Expressions\Expression;
8
use LaravelFreelancerNL\FluentAQL\Expressions\ListExpression;
9
use LaravelFreelancerNL\FluentAQL\Expressions\NullExpression;
10
use LaravelFreelancerNL\FluentAQL\Expressions\ObjectExpression;
11
use LaravelFreelancerNL\FluentAQL\Expressions\PredicateExpression;
12
use LaravelFreelancerNL\FluentAQL\Expressions\QueryExpression;
13
use LaravelFreelancerNL\FluentAQL\Expressions\StringExpression;
14
use LaravelFreelancerNL\FluentAQL\QueryBuilder;
15
16
trait NormalizesExpressions
17
{
18
19
    abstract public function bind($data, $to = null);
20
21
    /**
22
     * @param $argument
23
     * @param  array|null  $allowedExpressionTypes
24
     * @return Expression
25
     * @throws ExpressionTypeException
26
     */
27 5
    public function normalizeArgument($argument, $allowedExpressionTypes = null)
28
    {
29 5
        if ($argument instanceof Expression) {
30 4
            return $argument;
31
        }
32
33 5
        if (is_scalar($argument)) {
34 5
            return $this->normalizeScalar($argument, $allowedExpressionTypes);
35
        }
36
37 4
        if (is_null($argument)) {
38
            return new NullExpression();
39
        }
40
41 4
        return $this->normalizeCompound($argument, $allowedExpressionTypes);
42
    }
43
44
    /**
45
     * @param $argument
46
     * @param $allowedExpressionTypes
47
     *
48
     * @throws ExpressionTypeException
49
     *
50
     * @return BindExpression
51
     */
52 5
    protected function normalizeScalar($argument, $allowedExpressionTypes)
53
    {
54 5
        $argumentType = $this->determineArgumentType($argument, $allowedExpressionTypes);
55
56 5
        return $this->createExpression($argument, $argumentType);
57
    }
58
59 5
    protected function createExpression($argument, $argumentType)
60
    {
61 5
        $expressionType = $this->grammar->mapArgumentTypeToExpressionType($argumentType);
62 5
        if ($expressionType == 'Bind') {
63 1
            return $this->bind($argument);
64
        }
65 5
        if ($expressionType == 'CollectionBind') {
66
            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

66
            return $this->/** @scrutinizer ignore-call */ bindCollection($argument);
Loading history...
67
        }
68 5
        $expressionClass = '\LaravelFreelancerNL\FluentAQL\Expressions\\' . $expressionType . 'Expression';
69
70 5
        return new $expressionClass($argument);
71
    }
72
73 4
    protected function normalizeCompound($argument, $allowedExpressionTypes = null)
74
    {
75 4
        if (is_array($argument)) {
76 2
            return $this->normalizeArray($argument, $allowedExpressionTypes);
77
        }
78 4
        if (!is_iterable($argument)) {
79 4
            return $this->normalizeObject($argument, $allowedExpressionTypes);
80
        }
81
82
        return new ObjectExpression($this->normalizeIterable($argument, $allowedExpressionTypes));
83
    }
84
85
    /**
86
     * @param  array|object  $argument
87
     * @param  array|null  $allowedExpressionTypes
88
     *
89
     * @return array|object
90
     * @throws ExpressionTypeException
91
     */
92 2
    protected function normalizeIterable($argument, $allowedExpressionTypes = null)
93
    {
94 2
        foreach ($argument as $attribute => $value) {
95 2
            $argument[$attribute] = $this->normalizeArgument($value);
96
        }
97
98 2
        return $argument;
99
    }
100
101
    /**
102
     * @param array $predicates
103
     *
104
     * @return array
105
     */
106 4
    public function normalizePredicates($predicates): array
107
    {
108 4
        $normalizedPredicates = [];
109 4
        if (isset($predicates[1]) && is_string($predicates[1])) {
110 4
            $normalizedPredicates[] = $this->normalizePredicate($predicates);
111 4
            return $normalizedPredicates;
112
        }
113
114 4
        foreach ($predicates as $predicate) {
115 4
            if ($predicate instanceof PredicateExpression) {
116 4
                $normalizedPredicates[] = $predicate;
117 4
                continue;
118
            }
119 4
            $normalizedPredicates[] = $this->normalizePredicates($predicate);
120
        }
121
122 4
        return $normalizedPredicates;
123
    }
124
125 4
    protected function normalizePredicate($predicate)
126
    {
127 4
        $normalizedPredicate = [];
128
129 4
        $leftOperand = null;
130 4
        if (! $predicate[0] instanceof PredicateExpression) {
131 4
            $leftOperand = $this->normalizeArgument($predicate[0]);
132
        }
133
134 4
        $comparisonOperator = '==';
135 4
        if ($this->grammar->isComparisonOperator($predicate[1])) {
136 4
            $comparisonOperator = $predicate[1];
137
        }
138
139 4
        $rightOperand = null;
140 4
        if (! $predicate[2] instanceof PredicateExpression) {
141 4
            $rightOperand = $this->normalizeArgument($predicate[2]);
142
        }
143
144 4
        $logicalOperator = 'AND';
145
146 4
        if (isset($predicate[3]) && $this->grammar->isLogicalOperator($predicate[3])) {
147
            $logicalOperator = $predicate[3];
148
        }
149
150 4
        $normalizedPredicate[] = new PredicateExpression(
151 4
            $leftOperand,
0 ignored issues
show
Bug introduced by
It seems like $leftOperand can also be of type null; however, parameter $leftOperand of LaravelFreelancerNL\Flue...pression::__construct() does only seem to accept LaravelFreelancerNL\Flue...ons\ExpressionInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

151
            /** @scrutinizer ignore-type */ $leftOperand,
Loading history...
152 4
            $comparisonOperator,
153 4
            $rightOperand,
0 ignored issues
show
Bug introduced by
It seems like $rightOperand can also be of type null; however, parameter $rightOperand of LaravelFreelancerNL\Flue...pression::__construct() does only seem to accept LaravelFreelancerNL\Flue...ons\ExpressionInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

153
            /** @scrutinizer ignore-type */ $rightOperand,
Loading history...
154 4
            $logicalOperator
155
        );
156
157 4
        return $normalizedPredicate;
158
    }
159
160
    /**
161
     * Return the first matching expression type for the argument from the allowed types.
162
     *
163
     * @param string|iterable $argument
164
     * @param $allowedExpressionTypes
165
     *
166
     * @throws ExpressionTypeException
167
     *
168
     * @return mixed
169
     */
170 5
    protected function determineArgumentType($argument, $allowedExpressionTypes = null)
171
    {
172 5
        if (is_string($allowedExpressionTypes)) {
173 5
            $allowedExpressionTypes = [$allowedExpressionTypes];
174
        }
175 5
        if ($allowedExpressionTypes == null) {
176 4
            $allowedExpressionTypes = $this->grammar->getAllowedExpressionTypes();
177
        }
178
179 5
        foreach ($allowedExpressionTypes as $allowedExpressionType) {
180 5
            $check = 'is' . $allowedExpressionType;
181 5
            if ($allowedExpressionType == 'Reference' || $allowedExpressionType == 'RegisteredVariable') {
182 4
                if ($this->grammar->$check($argument, $this->variables)) {
183 4
                    return $allowedExpressionType;
184
                }
185
            }
186
187 5
            if ($this->grammar->$check($argument)) {
188 5
                return $allowedExpressionType;
189
            }
190
        }
191
192
        //Fallback to BindExpression if allowed
193
        if (isset($allowedExpressionTypes['Bind'])) {
194
            return 'Bind';
195
        }
196
197
        throw new ExpressionTypeException(
198
            "This argument, 
199
            '{$argument}', does not match one of these expression types: "
200
                . implode(', ', $allowedExpressionTypes)
201
                . '.'
202
        );
203
    }
204
205
    /**
206
     * @param $argument
207
     * @param $allowedExpressionTypes
208
     *
209
     * @return ListExpression|ObjectExpression
210
     */
211 2
    protected function normalizeArray($argument, $allowedExpressionTypes)
212
    {
213 2
        if ($this->grammar->isAssociativeArray($argument)) {
214 2
            return new ObjectExpression($this->normalizeIterable($argument, $allowedExpressionTypes));
215
        }
216
217
        return new ListExpression($this->normalizeIterable($argument, $allowedExpressionTypes));
0 ignored issues
show
Bug introduced by
It seems like $this->normalizeIterable...allowedExpressionTypes) can also be of type object; however, parameter $expression of LaravelFreelancerNL\Flue...pression::__construct() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

217
        return new ListExpression(/** @scrutinizer ignore-type */ $this->normalizeIterable($argument, $allowedExpressionTypes));
Loading history...
218
    }
219
220
    /**
221
     * @param $argument
222
     * @param $allowedExpressionTypes
223
     *
224
     * @return Expression
225
     */
226 4
    protected function normalizeObject($argument, $allowedExpressionTypes)
227
    {
228 4
        if ($argument instanceof \DateTimeInterface) {
229
            return new StringExpression($argument->format(\DateTime::ATOM));
230
        }
231
232 4
        if ($argument instanceof QueryBuilder) {
233 4
            return new QueryExpression($argument);
234
        }
235
236
        return new ObjectExpression($this->normalizeIterable((array) $argument, $allowedExpressionTypes));
237
    }
238
}
239