Passed
Pull Request — master (#33)
by Mark van den
16:57 queued 06:50
created

MySqlGrammar::compileGroupLimit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Staudenmeir\EloquentEagerLimit\Grammars;
4
5
use Illuminate\Database\Query\Builder;
6
use Illuminate\Database\Query\Grammars\MySqlGrammar as Base;
7
use Illuminate\Support\Str;
8
use PDO;
9
10
class MySqlGrammar extends Base
11
{
12
    use CompilesGroupLimit {
0 ignored issues
show
Bug introduced by
The trait Staudenmeir\EloquentEage...mars\CompilesGroupLimit requires the property $groupLimit which is not provided by Staudenmeir\EloquentEage...t\Grammars\MySqlGrammar.
Loading history...
13
        compileGroupLimit as compileGroupLimitParent;
14
    }
15
16
    /**
17
     * Determine whether to use a group limit clause for MySQL < 8.0.
18
     *
19
     * @param \Illuminate\Database\Query\Builder $query
20
     * @return bool
21
     */
22 32
    public function useLegacyGroupLimit(Builder $query)
23
    {
24 32
        $version = $query->getConnection()->getReadPdo()->getAttribute(PDO::ATTR_SERVER_VERSION);
25
26 32
        return version_compare($version, '8.0.11') < 0 && !Str::contains($version, 'MariaDB');
27
    }
28
29
    /**
30
     * Compile a group limit clause.
31
     *
32
     * @param \Illuminate\Database\Query\Builder $query
33
     * @return string
34
     */
35 32
    protected function compileGroupLimit(Builder $query)
36
    {
37 32
        return $this->useLegacyGroupLimit($query)
38 28
            ? $this->compileLegacyGroupLimit($query)
39 32
            : $this->compileGroupLimitParent($query);
40
    }
41
42
    /**
43
     * Compile a group limit clause for MySQL < 8.0.
44
     *
45
     * Derived from https://softonsofa.com/tweaking-eloquent-relations-how-to-get-n-related-models-per-parent/.
46
     *
47
     * @param \Illuminate\Database\Query\Builder $query
48
     * @return string
49
     */
50 28
    protected function compileLegacyGroupLimit(Builder $query)
51
    {
52 28
        $limit = (int) $query->groupLimit['value'];
53
54 28
        $offset = $query->offset;
55
56 28
        if (isset($offset)) {
57 12
            $limit += (int) $offset;
58
59 12
            $query->offset = null;
60
        }
61
62 28
        $column = last(explode('.', $query->groupLimit['column']));
63
64 28
        $column = $this->wrap($column);
65
66 28
        $partition = ', @laravel_row := if(@laravel_partition = '.$column.', @laravel_row + 1, 1) as laravel_row';
67
68 28
        $partition .= ', @laravel_partition := '.$column;
69
70 28
        $orders = (array) $query->orders;
71
72 28
        array_unshift($orders, ['column' => $query->groupLimit['column'], 'direction' => 'asc']);
73
74 28
        $query->orders = $orders;
75
76 28
        $components = $this->compileComponents($query);
77
78 28
        $sql = $this->concatenate($components);
79
80 28
        $from = '(select @laravel_row := 0, @laravel_partition := 0) as laravel_vars, ('.$sql.') as laravel_table';
81
82 28
        $sql = 'select laravel_table.*'.$partition.' from '.$from.' having laravel_row <= '.$limit;
83
84 28
        if (isset($offset)) {
85 12
            $sql .= ' and laravel_row > '.(int) $offset;
86
        }
87
88 28
        return $sql.' order by laravel_row';
89
    }
90
}
91