Paginator::compileSelectOrUnionAll()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 14
rs 10
cc 3
nc 3
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Lampager\Cake;
6
7
use Cake\ORM\Query\SelectQuery;
8
use Cake\ORM\Table;
9
use Generator;
10
use Lampager\Concerns\HasProcessor;
11
use Lampager\Contracts\Cursor;
12
use Lampager\Exceptions\Query\InsufficientConstraintsException;
13
use Lampager\Paginator as BasePaginator;
14
use Lampager\Query as LampagerQuery;
15
use Lampager\Query\Condition;
16
use Lampager\Query\ConditionGroup;
17
use Lampager\Query\Select;
18
use Lampager\Query\SelectOrUnionAll;
19
use Lampager\Query\UnionAll;
20
21
class Paginator extends BasePaginator
22
{
23
    use HasProcessor;
24
25
    /** @var SelectQuery $builder */
26
    public $builder;
27
28
    /**
29
     * Create paginator.
30
     *
31
     * @return static
32
     */
33
    public static function create(SelectQuery $builder)
34
    {
35
        return new static($builder);
36
    }
37
38
    /**
39
     * Construct paginator.
40
     */
41
    public function __construct(SelectQuery $builder)
42
    {
43
        $this->builder = $builder;
44
        $this->processor = new ArrayProcessor();
45
    }
46
47
    /**
48
     * Build CakePHP Query instance from Lampager Query config.
49
     */
50
    public function transform(LampagerQuery $query): SelectQuery
51
    {
52
        return $this->compileSelectOrUnionAll($query->selectOrUnionAll());
53
    }
54
55
    /**
56
     * Configure -> Transform.
57
     *
58
     * @param Cursor|int[]|string[] $cursor
59
     */
60
    public function build($cursor = []): SelectQuery
61
    {
62
        return $this->transform($this->configure($cursor));
63
    }
64
65
    /**
66
     * Execute query and paginate them.
67
     *
68
     * @param  Cursor|int[]|string[]  $cursor
69
     * @return mixed|PaginationResult
70
     */
71
    public function paginate($cursor = [])
72
    {
73
        $query = $this->configure($cursor);
74
        return $this->process($query, $this->transform($query)->toArray());
75
    }
76
77
    protected function compileSelectOrUnionAll(SelectOrUnionAll $selectOrUnionAll): SelectQuery
78
    {
79
        if ($selectOrUnionAll instanceof Select) {
80
            return $this->compileSelect($selectOrUnionAll);
81
        }
82
83
        if ($selectOrUnionAll instanceof UnionAll) {
84
            $supportQuery = $this->compileSelect($selectOrUnionAll->supportQuery());
85
            $mainQuery = $this->compileSelect($selectOrUnionAll->mainQuery());
86
            return $supportQuery->unionAll($mainQuery);
87
        }
88
89
        // @codeCoverageIgnoreStart
90
        throw new \LogicException('Unreachable here');
91
        // @codeCoverageIgnoreEnd
92
    }
93
94
    protected function compileSelect(Select $select): SelectQuery
95
    {
96
        if ($this->builder->clause('group') || $this->builder->clause('union')) {
97
            throw new InsufficientConstraintsException('group()/union() are not supported');
98
        }
99
100
        /** @var Table $repository */
101
        $repository = $this->builder->getRepository();
102
103
        /** @var SelectQuery $builder */
104
        $builder = $repository->selectQuery()
105
            ->where($this->builder->clause('where'))
106
            ->modifier($this->builder->clause('modifier'))
107
            ->join($this->builder->clause('join'))
108
            ->epilog($this->builder->clause('epilog'))
109
            ->setEagerLoader($this->builder->getEagerLoader());
110
111
        $this
112
            ->compileWhere($builder, $select)
113
            ->compileOrderBy($builder, $select)
114
            ->compileLimit($builder, $select);
115
116
        return $builder;
117
    }
118
119
    /**
120
     * @return $this
121
     */
122
    protected function compileWhere(SelectQuery $builder, Select $select)
123
    {
124
        $conditions = [];
125
        foreach ($select->where() as $group) {
126
            $conditions['OR'][] = iterator_to_array($this->compileWhereGroup($group));
127
        }
128
        $builder->where($conditions);
129
        return $this;
130
    }
131
132
    /**
133
     * @return \Generator<string,string>
134
     */
135
    protected function compileWhereGroup(ConditionGroup $group): Generator
136
    {
137
        /** @var Condition $condition */
138
        foreach ($group as $condition) {
139
            $column = $condition->left() . ' ' . $condition->comparator();
140
            $value = $condition->right();
141
            yield $column => $value;
142
        }
143
    }
144
145
    /**
146
     * @return $this
147
     */
148
    protected function compileOrderBy(SelectQuery $builder, Select $select)
149
    {
150
        $alias = $builder->getRepository()->getAlias();
151
152
        foreach ($select->orders() as $i => $order) {
153
            $column = $order->column();
154
            if (strpos($column, '.') === false) {
155
                $column = $alias . '.' . $column;
156
            }
157
            $builder->orderBy([$column => $order->order()], $i === 0);
158
        }
159
        return $this;
160
    }
161
162
    /**
163
     * @return $this
164
     */
165
    protected function compileLimit(SelectQuery $builder, Select $select)
166
    {
167
        $builder->limit($select->limit()->toInteger());
168
        return $this;
169
    }
170
171
    /**
172
     * Returns an array that can be used to describe the internal state of this object.
173
     */
174
    public function __debugInfo(): array
175
    {
176
        $query = $this->configure();
177
178
        return [
179
            'query' => [
180
                'orders' => $query->orders(),
181
                'limit' => $query->limit(),
182
                'forward' => $query->forward(),
183
                'inclusive' => $query->inclusive(),
184
                'seekable' => $query->seekable(),
185
            ],
186
        ];
187
    }
188
}
189