BuildsSubqueries::createSub()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.2098

Importance

Changes 0
Metric Value
cc 3
eloc 7
c 0
b 0
f 0
nc 4
nop 2
dl 0
loc 18
ccs 5
cts 7
cp 0.7143
crap 3.2098
rs 10
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent\Query\Concerns;
4
5
use Closure;
6
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
7
use Illuminate\Database\Eloquent\Builder as IlluminateEloquentBuilder;
8
use Illuminate\Database\Eloquent\Relations\Relation;
9
use Illuminate\Database\Query\Builder as IlluminateQueryBuilder;
10
use InvalidArgumentException;
11
use LaravelFreelancerNL\Aranguent\Query\Builder;
12
use LaravelFreelancerNL\Aranguent\Query\Grammar;
13
14
trait BuildsSubqueries
15
{
16
    /**
17
     * IN SQL subqueries in selects and where's need to return a single value,
18
     * whereas subqueries in joins return an object. This variable lets the
19
     * compiler know how to return a single value.
20
     *
21
     * @var bool
22
     */
23
    public bool $returnSingleValue = false;
24
25
    /**
26
     * Creates a subquery and parse it.
27
     *
28
     * @param  \Closure|IlluminateQueryBuilder|IlluminateEloquentBuilder|string $query
29
     * @return array<mixed>
30
     *
31
     * @SuppressWarnings("PHPMD.BooleanArgumentFlag")
32
     */
33 14
    public function createSub($query, bool $returnSingleValue = false)
34
    {
35
        // If the given query is a Closure, we will execute it while passing in a new
36
        // query instance to the Closure. This will give the developer a chance to
37
        // format and work with the query before we cast it to a raw SQL string.
38 14
        if ($query instanceof Closure) {
39
            $callback = $query;
40
41
            $callback($query = $this->forSubQuery());
42
        }
43
44
        assert($query instanceof Builder);
45
46 14
        if ($returnSingleValue) {
47 2
            $query->returnSingleValue = $returnSingleValue;
48
        }
49
50 14
        return $this->parseSub($query);
51
    }
52
53
    /**
54
     * Create a new query instance for sub-query.
55
     *
56
     * @return \Illuminate\Database\Query\Builder
57
     */
58 5
    protected function forSubQuery()
59
    {
60 5
        return $this->newQuery();
0 ignored issues
show
Bug introduced by
It seems like newQuery() 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

60
        return $this->/** @scrutinizer ignore-call */ newQuery();
Loading history...
61
    }
62
63
    /**
64
     * @param IlluminateQueryBuilder $query
65
     * @return bool
66
     */
67 40
    protected function hasLimitOfOne(IlluminateQueryBuilder $query)
68
    {
69
        assert($query instanceof Builder);
70
71 40
        if ($query->limit === 1 || $query->returnSingleValue === true) {
72 5
            return true;
73
        }
74
75 35
        return false;
76
    }
77
78
    /**
79
     * Parse the subquery into AQL and bindings.
80
     *
81
     * @param IlluminateEloquentBuilder|IlluminateQueryBuilder|Relation|string  $query
82
     * @return array<mixed>
83
     *
84
     * @throws \InvalidArgumentException
85
     */
86 40
    protected function parseSub($query)
87
    {
88 40
        if (is_string($query)) {
89
            return [$query, []];
90
        }
91
92 40
        if ($query instanceof EloquentBuilder || $query instanceof Relation) {
93
            $query = $query->getQuery();
94
        }
95
96 40
        if ($query instanceof self) {
97 40
            $this->exchangeTableAliases($query);
0 ignored issues
show
Bug introduced by
It seems like exchangeTableAliases() 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

97
            $this->/** @scrutinizer ignore-call */ 
98
                   exchangeTableAliases($query);
Loading history...
98
99 40
            $this->importBindings($query);
0 ignored issues
show
Bug introduced by
It seems like importBindings() 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

99
            $this->/** @scrutinizer ignore-call */ 
100
                   importBindings($query);
Loading history...
100
101
            assert($this->grammar instanceof Grammar);
102 40
            $queryString = $this->grammar->wrapSubquery($query->toSql());
0 ignored issues
show
Bug introduced by
It seems like toSql() 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
            $queryString = $this->grammar->wrapSubquery($query->/** @scrutinizer ignore-call */ toSql());
Loading history...
103
104 40
            if ($this->hasLimitOfOne($query)) {
0 ignored issues
show
Bug introduced by
$query of type LaravelFreelancerNL\Aran...ncerns\BuildsSubqueries is incompatible with the type Illuminate\Database\Query\Builder expected by parameter $query of LaravelFreelancerNL\Aran...ueries::hasLimitOfOne(). ( Ignorable by Annotation )

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

104
            if ($this->hasLimitOfOne(/** @scrutinizer ignore-type */ $query)) {
Loading history...
105 5
                $queryString = 'FIRST(' . $queryString . ')';
106
            }
107
108 40
            return [$queryString, $query->getBindings()];
0 ignored issues
show
Bug introduced by
It seems like getBindings() 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

108
            return [$queryString, $query->/** @scrutinizer ignore-call */ getBindings()];
Loading history...
109
        }
110
111
        throw new InvalidArgumentException(
112
            'A subquery must be a query builder instance, a Relation, a Closure, or a string.',
113
        );
114
    }
115
}
116