Passed
Pull Request — master (#13)
by Bas
05:52
created

NormalizesExpressions   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 209
Duplicated Lines 0 %

Test Coverage

Coverage 86.42%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 73
c 1
b 0
f 1
dl 0
loc 209
ccs 70
cts 81
cp 0.8642
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 18 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 4
        if (isset($predicates[1]) && is_string($predicates[1]) && $this->grammar->isComparisonOperator($predicates[1])) {
112 4
            return $this->normalizePredicate($predicates);
113
        }
114
115 4
        foreach ($predicates as $predicate) {
116 4
            if ($predicate instanceof PredicateExpression) {
117 4
                $normalizedPredicates[] = $predicate;
118 4
                continue;
119
            }
120 4
            $normalizedPredicates[] = $this->normalizePredicates($predicate);
121
        }
122
123 4
        return $normalizedPredicates;
124
    }
125
126 4
    protected function normalizePredicate($predicate)
127
    {
128 4
        $leftOperand = null;
129 4
        if (! $predicate[0] instanceof PredicateExpression) {
130 4
            $leftOperand = $this->normalizeArgument($predicate[0]);
131
        }
132
133 4
        $comparisonOperator = $predicate[1];
134
135 4
        $rightOperand = null;
136 4
        if (! $predicate[2] instanceof PredicateExpression) {
137 4
            $rightOperand = $this->normalizeArgument($predicate[2]);
138
        }
139
140 4
        $logicalOperator = 'AND';
141 4
        if (isset($predicate[3]) && $this->grammar->isLogicalOperator($predicate[3])) {
142
            $logicalOperator = $predicate[3];
143
        }
144
145 4
       return new PredicateExpression(
146 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

146
            /** @scrutinizer ignore-type */ $leftOperand,
Loading history...
147 4
            $comparisonOperator,
148 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

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

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