Failed Conditions
Push — refactor/improve-static-analys... ( ba8000...c6edde )
by Bas
14:06
created

QueriesAranguentRelationships::withAggregate()   C

Complexity

Conditions 13
Paths 149

Size

Total Lines 87
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 14.0154

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 13
eloc 43
c 2
b 0
f 0
nc 149
nop 3
dl 0
loc 87
rs 6.2083
ccs 18
cts 22
cp 0.8182
crap 14.0154

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace LaravelFreelancerNL\Aranguent\Eloquent\Concerns;
6
7
use Illuminate\Database\Eloquent\Builder;
8
use Illuminate\Database\Eloquent\Builder as IlluminateBuilder;
9
use Illuminate\Database\Eloquent\Builder as IlluminateEloquentBuilder;
10
use Illuminate\Database\Query\Builder as IlluminateQueryBuilder;
11
use Illuminate\Database\Query\Expression;
12
use Illuminate\Support\Str;
13
use LaravelFreelancerNL\Aranguent\Query\Builder as QueryBuilder;
14
use LaravelFreelancerNL\FluentAQL\Expressions\FunctionExpression;
15
use LaravelFreelancerNL\FluentAQL\QueryBuilder as ArangoQueryBuilder;
16
17
trait QueriesAranguentRelationships
18
{
19
    /**
20
     * Add a sub-query count clause to this query.
21
     *
22
     * @param  \Illuminate\Database\Query\Builder  $query
23
     * @param  string  $operator
24 1
     * @param  int  $count
25
     * @param  string  $boolean
26
     * @return $this
27
     */
28
    protected function addWhereCountQuery(IlluminateQueryBuilder $query, $operator = '>=', $count = 1, $boolean = 'and')
29
    {
30
31 1
        $this->getQuery()->exchangeTableAliases($query);
0 ignored issues
show
Bug introduced by
It seems like getQuery() 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

31
        $this->/** @scrutinizer ignore-call */ 
32
               getQuery()->exchangeTableAliases($query);
Loading history...
32
33 1
        $this->getQuery()->importBindings($query);
34 1
35
        return $this->where(
0 ignored issues
show
Bug introduced by
It seems like where() 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

35
        return $this->/** @scrutinizer ignore-call */ where(
Loading history...
36 1
            new Expression('LENGTH(('.$query->toSql().'))'),
37
            $operator,
38
            is_numeric($count) ? new Expression($count) : $count,
0 ignored issues
show
introduced by
The condition is_numeric($count) is always true.
Loading history...
39
            $boolean
40
        );
41
    }
42
43
    /**
44
     * Merge the where constraints from another query to the current query.
45
     *
46
     * @param IlluminateEloquentBuilder $from
47
     * @return IlluminateEloquentBuilder|static
48
     */
49
    public function mergeConstraintsFrom(Builder $from)
50
    {
51 137
        $whereBindings = $this->getQuery()->getBindings() ?? [];
52
53 137
        $wheres = $from->getQuery()->from !== $this->getQuery()->from
54
            ? $this->requalifyWhereTables(
0 ignored issues
show
Bug introduced by
It seems like requalifyWhereTables() 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

54
            ? $this->/** @scrutinizer ignore-call */ requalifyWhereTables(
Loading history...
55 137
                $from->getQuery()->wheres,
56 137
                $from->getQuery()->grammar->getValue($from->getQuery()->from),
57
                $this->getModel()->getTable()
0 ignored issues
show
Bug introduced by
It seems like getModel() 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

57
                $this->/** @scrutinizer ignore-call */ 
58
                       getModel()->getTable()
Loading history...
58
            ) : $from->getQuery()->wheres;
59 1
60 1
        // Here we have some other query that we want to merge the where constraints from. We will
61
        // copy over any where constraints on the query as well as remove any global scopes the
62
        // query might have removed. Then we will return ourselves with the finished merging.
63 1
        return $this->withoutGlobalScopes(
0 ignored issues
show
Bug introduced by
It seems like withoutGlobalScopes() 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

63
        return $this->/** @scrutinizer ignore-call */ withoutGlobalScopes(
Loading history...
64
            $from->removedScopes()
65 1
        )->mergeWheres(
66
            $wheres, $whereBindings
67
        );
68
    }
69 1
70
    /**
71 1
     * Add subselect queries to include an aggregate value for a relationship.
72
     *
73 1
     * @param  mixed  $relations
74
     * @param  string  $column
75
     * @param  string  $function
76
     * @return $this
77 1
     */
78
    public function withAggregate($relations, $column, $function = null)
79
    {
80
        if (empty($relations)) {
81
            return $this;
82 1
        }
83 1
84
        if (is_null($this->query->columns)) {
85
            $this->query->select([$this->query->from.'.*']);
86
        }
87 1
88
        $relations = is_array($relations) ? $relations : [$relations];
89 1
90
        foreach ($this->parseWithRelations($relations) as $name => $constraints) {
0 ignored issues
show
Bug introduced by
It seems like parseWithRelations() 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

90
        foreach ($this->/** @scrutinizer ignore-call */ parseWithRelations($relations) as $name => $constraints) {
Loading history...
91
            // First we will determine if the name has been aliased using an "as" clause on the name
92
            // and if it has we will extract the actual relationship name and the desired name of
93
            // the resulting column. This allows multiple aggregates on the same relationships.
94 1
            $segments = explode(' ', $name);
95
96 1
            unset($alias);
97
98
            if (count($segments) === 3 && Str::lower($segments[1]) === 'as') {
99
                [$name, $alias] = [$segments[0], $segments[2]];
100
            }
101 1
102
            $relation = $this->getRelationWithoutConstraints($name);
0 ignored issues
show
Bug introduced by
It seems like getRelationWithoutConstraints() 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

102
            /** @scrutinizer ignore-call */ 
103
            $relation = $this->getRelationWithoutConstraints($name);
Loading history...
103
104
            if ($function) {
105
                $hashedColumn = $this->getRelationHashedColumn($column, $relation);
0 ignored issues
show
Bug introduced by
It seems like getRelationHashedColumn() 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

105
                /** @scrutinizer ignore-call */ 
106
                $hashedColumn = $this->getRelationHashedColumn($column, $relation);
Loading history...
106 1
107 1
                $wrappedColumn = $this->getQuery()->getGrammar()->wrap(
108
                    $column === '*' ? $column : $relation->getRelated()->qualifyColumn($hashedColumn)
109
                );
110
111 1
                $expression = $function === 'exists' ? $wrappedColumn : sprintf('%s(%s)', $function, $wrappedColumn);
112 1
            } else {
113
                $expression = $column;
114
            }
115
116
            // Here, we will grab the relationship sub-query and prepare to add it to the main query
117 1
            // as a sub-select. First, we'll get the "has" query and use that to get the relation
118
            // sub-query. We'll format this relationship name and append this column if needed.
119
            $query = $relation->getRelationExistenceQuery(
120 1
                $relation->getRelated()->newQuery(), $this, new Expression($expression)
121
            )->setBindings([], 'select');
122 1
123 1
            $query->callScope($constraints);
124 1
125
            $query = $query->mergeConstraintsFrom($relation->getQuery())->toBase();
126 1
127
            // If the query contains certain elements like orderings / more than one column selected
128
            // then we will remove those elements from the query so that it will execute properly
129
            // when given to the database. Otherwise, we may receive SQL errors or poor syntax.
130
            $query->orders = null;
131 1
            $query->setBindings([], 'order');
132
133
            if (count($query->columns) > 1) {
134
                $query->columns = [$query->columns[0]];
135
                $query->bindings['select'] = [];
136
            }
137
138
            // Finally, we will make the proper column alias to the query and run this sub-select on
139
            // the query builder. Then, we will return the builder instance back to the developer
140
            // for further constraint chaining that needs to take place on the query as needed.
141
            $alias ??= Str::snake(
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $alias seems to be defined later in this foreach loop on line 99. Are you sure it is defined here?
Loading history...
142
                preg_replace('/[^[:alnum:][:space:]_]/u', '', "$name $function $column")
143
            );
144
145
            if ($function === 'exists') {
146
                //FIXME: test for results from the subquery -> whereHas?
147
                $this->selectRaw(
0 ignored issues
show
Bug introduced by
It seems like selectRaw() 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

147
                $this->/** @scrutinizer ignore-call */ 
148
                       selectRaw(
Loading history...
148
                    sprintf('exists(%s) as %s', $query->toSql(), $this->getQuery()->grammar->wrap($alias)),
149
                    $query->getBindings()
150
                )->withCasts([$alias => 'bool']);
151
            } else {
152
                if ($function === null) {
153
                    $query->limit(1);
154
                }
155
156
                $this->getQuery()->exchangeTableAliases($query);
157
                $this->getQuery()->importBindings($query);
158
159
                $this->set($alias, new Expression(strtoupper($function).'(('.$query->toSql().'))'), 'postIterationVariables');
0 ignored issues
show
Bug introduced by
It seems like set() 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

159
                $this->/** @scrutinizer ignore-call */ 
160
                       set($alias, new Expression(strtoupper($function).'(('.$query->toSql().'))'), 'postIterationVariables');
Loading history...
160
                $this->addSelect($alias);
0 ignored issues
show
Bug introduced by
It seems like addSelect() 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

160
                $this->/** @scrutinizer ignore-call */ 
161
                       addSelect($alias);
Loading history...
161
            }
162
        }
163
164
        return $this;
165
    }
166
}
167