Passed
Push — master ( 0d1e3a...a8104a )
by Jonas
11:45
created

CompilesMySqlGroupLimit   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 79
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 27
c 1
b 0
f 0
dl 0
loc 79
ccs 27
cts 27
cp 1
rs 10
wmc 7

3 Methods

Rating   Name   Duplication   Size   Complexity  
A compileGroupLimit() 0 5 2
A compileLegacyGroupLimit() 0 39 3
A useLegacyGroupLimit() 0 5 2
1
<?php
2
3
namespace Staudenmeir\EloquentEagerLimit\Grammars\Traits;
4
5
use Illuminate\Database\Query\Builder;
6
use Illuminate\Support\Str;
7
use PDO;
8
9
trait CompilesMySqlGroupLimit
10
{
11
    use CompilesGroupLimit {
12
        compileGroupLimit as compileGroupLimitParent;
13
    }
14
15
    /**
16
     * Determine whether to use a group limit clause for MySQL < 8.0.
17
     *
18
     * @param \Illuminate\Database\Query\Builder $query
19
     * @return bool
20
     */
21 32
    public function useLegacyGroupLimit(Builder $query)
22
    {
23 32
        $version = $query->getConnection()->getReadPdo()->getAttribute(PDO::ATTR_SERVER_VERSION);
24
25 32
        return version_compare($version, '8.0.11') < 0 && !Str::contains($version, 'MariaDB');
26
    }
27
28
    /**
29
     * Compile a group limit clause.
30
     *
31
     * @param \Illuminate\Database\Query\Builder $query
32
     * @return string
33
     */
34 32
    protected function compileGroupLimit(Builder $query)
35
    {
36 32
        return $this->useLegacyGroupLimit($query)
37 28
            ? $this->compileLegacyGroupLimit($query)
38 32
            : $this->compileGroupLimitParent($query);
39
    }
40
41
    /**
42
     * Compile a group limit clause for MySQL < 8.0.
43
     *
44
     * Derived from https://softonsofa.com/tweaking-eloquent-relations-how-to-get-n-related-models-per-parent/.
45
     *
46
     * @param \Illuminate\Database\Query\Builder $query
47
     * @return string
48
     */
49 28
    protected function compileLegacyGroupLimit(Builder $query)
50
    {
51 28
        $limit = (int) $query->groupLimit['value'];
0 ignored issues
show
Bug introduced by
The property groupLimit does not seem to exist on Illuminate\Database\Query\Builder.
Loading history...
52
53 28
        $offset = $query->offset;
54
55 28
        if (isset($offset)) {
56 12
            $limit += (int) $offset;
57
58 12
            $query->offset = null;
59
        }
60
61 28
        $column = last(explode('.', $query->groupLimit['column']));
62
63 28
        $column = $this->wrap($column);
0 ignored issues
show
Bug introduced by
It seems like wrap() 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
        /** @scrutinizer ignore-call */ 
64
        $column = $this->wrap($column);
Loading history...
64
65 28
        $partition = ', @laravel_row := if(@laravel_partition = '.$column.', @laravel_row + 1, 1) as laravel_row';
66
67 28
        $partition .= ', @laravel_partition := '.$column;
68
69 28
        $orders = (array) $query->orders;
70
71 28
        array_unshift($orders, ['column' => $query->groupLimit['column'], 'direction' => 'asc']);
72
73 28
        $query->orders = $orders;
74
75 28
        $components = $this->compileComponents($query);
0 ignored issues
show
Bug introduced by
It seems like compileComponents() 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

75
        /** @scrutinizer ignore-call */ 
76
        $components = $this->compileComponents($query);
Loading history...
76
77 28
        $sql = $this->concatenate($components);
0 ignored issues
show
Bug introduced by
It seems like concatenate() 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

77
        /** @scrutinizer ignore-call */ 
78
        $sql = $this->concatenate($components);
Loading history...
78
79 28
        $from = '(select @laravel_row := 0, @laravel_partition := 0) as laravel_vars, ('.$sql.') as laravel_table';
80
81 28
        $sql = 'select laravel_table.*'.$partition.' from '.$from.' having laravel_row <= '.$limit;
82
83 28
        if (isset($offset)) {
84 12
            $sql .= ' and laravel_row > '.(int) $offset;
85
        }
86
87 28
        return $sql.' order by laravel_row';
88
    }
89
}
90