Passed
Pull Request — master (#13)
by Bas
03:44 queued 01:39
created

NormalizesExpressions   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Test Coverage

Coverage 86.75%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 76
c 2
b 0
f 1
dl 0
loc 213
ccs 72
cts 83
cp 0.8675
rs 9.44
wmc 37

10 Methods

Rating   Name   Duplication   Size   Complexity  
A normalizeArgument() 0 15 4
A normalizeIterable() 0 7 2
A normalizeCompound() 0 10 3
A createExpression() 0 12 3
A normalizeScalar() 0 5 1
A normalizeArray() 0 7 2
A normalizePredicate() 0 24 5
B determineArgumentType() 0 27 8
A normalizePredicates() 0 22 6
A normalizeObject() 0 11 3
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|object
105
     */
106 4
    public function normalizePredicates(array $predicates)
107
    {
108 4
        $normalizedPredicates = [];
109
110
        //Check if predicates is in fact a single predicate
111
        if (
112 4
            isset($predicates[1])
113 4
            && is_string($predicates[1])
114 4
            && $this->grammar->isComparisonOperator($predicates[1])
115
        ) {
116 4
            return $this->normalizePredicate($predicates);
117
        }
118
119 4
        foreach ($predicates as $predicate) {
120 4
            if ($predicate instanceof PredicateExpression) {
121 4
                $normalizedPredicates[] = $predicate;
122 4
                continue;
123
            }
124 4
            $normalizedPredicates[] = $this->normalizePredicates($predicate);
125
        }
126
127 4
        return $normalizedPredicates;
128
    }
129
130 4
    protected function normalizePredicate($predicate)
131
    {
132 4
        $leftOperand = null;
133 4
        if (! $predicate[0] instanceof PredicateExpression) {
134 4
            $leftOperand = $this->normalizeArgument($predicate[0]);
135
        }
136
137 4
        $comparisonOperator = $predicate[1];
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 4
        if (isset($predicate[3]) && $this->grammar->isLogicalOperator($predicate[3])) {
146
            $logicalOperator = $predicate[3];
147
        }
148
149 4
        return new PredicateExpression(
150 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

150
            /** @scrutinizer ignore-type */ $leftOperand,
Loading history...
151 4
            $comparisonOperator,
152 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

152
            /** @scrutinizer ignore-type */ $rightOperand,
Loading history...
153 4
            $logicalOperator
154
        );
155
    }
156
157
    /**
158
     * Return the first matching expression type for the argument from the allowed types.
159
     *
160
     * @param string|iterable $argument
161
     * @param $allowedExpressionTypes
162
     *
163
     * @throws ExpressionTypeException
164
     *
165
     * @return mixed
166
     */
167 5
    protected function determineArgumentType($argument, $allowedExpressionTypes = null)
168
    {
169 5
        if (is_string($allowedExpressionTypes)) {
170 5
            $allowedExpressionTypes = [$allowedExpressionTypes];
171
        }
172 5
        if ($allowedExpressionTypes == null) {
173 4
            $allowedExpressionTypes = $this->grammar->getAllowedExpressionTypes();
174
        }
175
176 5
        foreach ($allowedExpressionTypes as $allowedExpressionType) {
177 5
            $check = 'is' . $allowedExpressionType;
178 5
            if ($allowedExpressionType == 'Reference' || $allowedExpressionType == 'RegisteredVariable') {
179 4
                if ($this->grammar->$check($argument, $this->variables)) {
180 4
                    return $allowedExpressionType;
181
                }
182
            }
183
184 5
            if ($this->grammar->$check($argument)) {
185 5
                return $allowedExpressionType;
186
            }
187
        }
188
189
        throw new ExpressionTypeException(
190
            "This argument, 
191
            '{$argument}', does not match one of these expression types: "
192
                . implode(', ', $allowedExpressionTypes)
193
                . '.'
194
        );
195
    }
196
197
    /**
198
     * @param $argument
199
     * @param $allowedExpressionTypes
200
     *
201
     * @return ListExpression|ObjectExpression
202
     */
203 2
    protected function normalizeArray($argument, $allowedExpressionTypes)
204
    {
205 2
        if ($this->grammar->isAssociativeArray($argument)) {
206 2
            return new ObjectExpression($this->normalizeIterable($argument, $allowedExpressionTypes));
207
        }
208
209
        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

209
        return new ListExpression(/** @scrutinizer ignore-type */ $this->normalizeIterable($argument, $allowedExpressionTypes));
Loading history...
210
    }
211
212
    /**
213
     * @param $argument
214
     * @param $allowedExpressionTypes
215
     *
216
     * @return Expression
217
     */
218 4
    protected function normalizeObject($argument, $allowedExpressionTypes)
219
    {
220 4
        if ($argument instanceof \DateTimeInterface) {
221
            return new StringExpression($argument->format(\DateTime::ATOM));
222
        }
223
224 4
        if ($argument instanceof QueryBuilder) {
225 4
            return new QueryExpression($argument);
226
        }
227
228
        return new ObjectExpression($this->normalizeIterable((array) $argument, $allowedExpressionTypes));
229
    }
230
}
231