Passed
Pull Request — master (#7)
by Chito
02:51
created

LampagerTransformer::transform()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 32
rs 9.408
c 0
b 0
f 0
cc 2
nc 1
nop 1
ccs 9
cts 9
cp 1
crap 2

1 Method

Rating   Name   Duplication   Size   Complexity  
A 0 31 2
1
<?php
2
3
App::uses('LampagerArrayCursor', 'Lampager.Model');
4
App::uses('LampagerPaginator', 'Lampager.Model');
5
App::uses('Sqlite', 'Model/Datasource/Database');
6
7
use Lampager\Cursor;
0 ignored issues
show
Bug introduced by
The type Lampager\Cursor was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Lampager\Query;
9
use Lampager\Query\Select;
10
use Lampager\Query\SelectOrUnionAll;
11
use Lampager\Query\UnionAll;
12
use Lampager\Query\ConditionGroup;
13
14
class LampagerTransformer
15
{
16
    /** @var LampagerPaginator */
17
    protected $paginator;
18
19
    public function __construct(LampagerPaginator $paginator)
20 36
    {
21
        $this->paginator = $paginator;
22 36
    }
23 36
24
    /**
25
     * Transform Query to CakePHP query.
26
     *
27
     * @param  Query $query Query.
28
     * @return array        Options for Model::find.
29
     */
30
    public function transform(Query $query)
31 32
    {
32
        $model = $this->paginator->builder;
33 32
        return [
34
            // Compiled by static::compileSelect
35
            'conditions' => null,
36 32
37
            // Compiled by static::compileLimit
38
            'limit' => null,
39
40
            // Sort the result set
41
            'order' => $this->compileOrderBy($query->selectOrUnionAll()),
42
43
            // Used along with ArrayProcessor
44
            'config' => $query,
45 32
46
            // Create subquery and inner join with it
47
            'joins' => array_merge(
48 32
                [
49
                    [
50
                        'type' => 'INNER',
51 32
                        'table' => $this->compileSelectOrUnionAll($query->selectOrUnionAll()),
52 32
                        'alias' => LampagerPaginator::class,
53
                        'conditions' => [
54
                            LampagerPaginator::class . ".{$model->primaryKey} = {$model->alias}.{$model->primaryKey}",
55 32
                        ],
56
                    ],
57
                ],
58
                $this->paginator->query['joins'] ?: []
59 32
            ),
60
        ] + $this->paginator->query;
61 32
    }
62
63
    /**
64
     * Build query from the cursor.
65
     *
66
     * @param  Cursor|int[]|string[] $cursor Cursor.
67
     * @return array                         Options for Model::find.
68
     */
69
    public function build($cursor = [])
70 32
    {
71
        return $this->transform($this->paginator->configure(new LampagerArrayCursor($this->paginator->builder, $cursor)));
0 ignored issues
show
Bug introduced by
It seems like $cursor can also be of type Lampager\Cursor; however, parameter $cursor of LampagerArrayCursor::__construct() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

71
        return $this->transform($this->paginator->configure(new LampagerArrayCursor($this->paginator->builder, /** @scrutinizer ignore-type */ $cursor)));
Loading history...
72 32
    }
73
74
    /**
75
     * @param  SelectOrUnionAll $selectOrUnionAll
76
     * @return string
77
     */
78
    protected function compileSelectOrUnionAll(SelectOrUnionAll $selectOrUnionAll)
79 32
    {
80
        if ($selectOrUnionAll instanceof Select) {
81 32
            return '(' . $this->compileSelect($selectOrUnionAll) . ')';
82 16
        }
83
84 16
        if ($selectOrUnionAll instanceof UnionAll) {
85 16
            $supportQuery = $this->compileSelect($selectOrUnionAll->supportQuery());
86 16
            $mainQuery = $this->compileSelect($selectOrUnionAll->mainQuery());
87 16
88
            if ($this->paginator->builder->getDataSource() instanceof Sqlite) {
89
                return '(SELECT * FROM (' . $supportQuery . ') UNION ALL SELECT * FROM (' . $mainQuery . '))';
90
            }
91
92
            return '((' . $supportQuery . ') UNION ALL (' . $mainQuery . '))';
93
        }
94
95
        // @codeCoverageIgnoreStart
96
        throw new \LogicException('Unreachable here');
97
        // @codeCoverageIgnoreEnd
98
    }
99 32
100
    /**
101 32
     * @param  Select $select
102 32
     * @return string
103
     */
104
    protected function compileSelect(Select $select)
105 32
    {
106
        $model = $this->paginator->builder;
107 32
        $query = $this->paginator->query;
108 32
109 32
        /** @var DboSource $db */
110 32
        $db = $model->getDataSource();
111 32
112 32
        return $db->buildStatement([
113
            'limit' => $this->compileLimit($select),
114 32
            'order' => $this->compileOrderBy($select),
115 32
            'conditions' => array_merge_recursive(
116
                $this->compileWhere($select),
117 32
                $query['conditions'] ?: []
118
            ),
119 32
            'alias' => $model->alias,
120
            'table' => $db->fullTableName($model),
121
            'fields' => [
122
                $db->name("{$model->alias}.{$model->primaryKey}"),
123
            ],
124
        ], $model);
125
    }
126 32
127
    /**
128 32
     * @param  Select   $select
129 32
     * @return string[]
130 16
     */
131
    protected function compileWhere(Select $select)
132 32
    {
133
        $conditions = [];
134
        foreach ($select->where() as $group) {
135
            $conditions['OR'][] = iterator_to_array($this->compileWhereGroup($group));
136
        }
137
        return $conditions;
138
    }
139 16
140
    /**
141 16
     * @param  ConditionGroup     $group
142 16
     * @return \Generator<string,string>
143 16
     */
144 16
    protected function compileWhereGroup(ConditionGroup $group)
145
    {
146 16
        foreach ($group as $condition) {
147
            $column = $condition->left() . ' ' . $condition->comparator();
148
            $value = $condition->right();
149
            yield $column => $value;
150
        }
151
    }
152 32
153
    /**
154 32
     * @param  SelectOrUnionAll $selectOrUnionAll
155 32
     * @return string[]
156 32
     */
157
    protected function compileOrderBy(SelectOrUnionAll $selectOrUnionAll)
158 32
    {
159
        /** @var Select $select */
160
        if ($selectOrUnionAll instanceof Select) {
161
            $select = $selectOrUnionAll;
162
        }
163
        if ($selectOrUnionAll instanceof UnionAll) {
164
            $select = $selectOrUnionAll->mainQuery();
165 32
        }
166
167 32
        // @codeCoverageIgnoreStart
168
        if (!isset($select)) {
169
            throw new \LogicException('Unreachable here');
170
        }
171
        // @codeCoverageIgnoreEnd
172
173
        $orders = [];
174
        foreach ($select->orders() as $order) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $select does not seem to be defined for all execution paths leading up to this point.
Loading history...
175
            $orders[$order->column()] = $order->order();
176
        }
177
        return $orders;
178
    }
179
180
    /**
181
     * @param  Select $select
182
     * @return int
183
     */
184
    protected function compileLimit(Select $select)
185
    {
186
        return $select->limit()->toInteger();
187
    }
188
}
189