LampagerTransformer::compileSelectOrUnionAll()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 4
eloc 9
c 2
b 0
f 1
nc 4
nop 1
dl 0
loc 19
ccs 7
cts 7
cp 1
crap 4
rs 9.9666
1
<?php
2
3
App::uses('LampagerPaginator', 'Lampager.Model');
4
App::uses('Sqlite', 'Model/Datasource/Database');
5
6
use Lampager\Query;
7
use Lampager\Query\ConditionGroup;
8
use Lampager\Query\Select;
9
use Lampager\Query\SelectOrUnionAll;
10
use Lampager\Query\UnionAll;
11
12
class LampagerTransformer
13
{
14
    /** @var Model */
15
    protected $builder;
16
17
    /** @var array */
18
    protected $options;
19
20 36
    public function __construct(Model $builder, array $options)
21
    {
22 36
        $this->builder = $builder;
23 36
        $this->options = $options;
24
    }
25
26
    /**
27
     * Transform Query to CakePHP query.
28
     *
29
     * @return array Options for Model::find.
30
     */
31 32
    public function transform(Query $query)
32
    {
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 . ".{$this->builder->primaryKey} = {$this->builder->alias}.{$this->builder->primaryKey}",
55 32
                        ],
56
                    ],
57
                ],
58
                isset($this->options['joins']) ? $this->options['joins'] : []
59 32
            ),
60
        ] + $this->options;
61 32
    }
62
63
    /**
64
     * @param  Select|UnionAll $selectOrUnionAll
65
     * @return string
66
     */
67
    protected function compileSelectOrUnionAll(SelectOrUnionAll $selectOrUnionAll)
68
    {
69
        if ($selectOrUnionAll instanceof Select) {
70 32
            return '(' . $this->compileSelect($selectOrUnionAll) . ')';
71
        }
72 32
73
        if ($selectOrUnionAll instanceof UnionAll) {
74
            $supportQuery = $this->compileSelect($selectOrUnionAll->supportQuery());
75
            $mainQuery = $this->compileSelect($selectOrUnionAll->mainQuery());
76
77
            if ($this->builder->getDataSource() instanceof Sqlite) {
78
                return '(SELECT * FROM (' . $supportQuery . ') UNION ALL SELECT * FROM (' . $mainQuery . '))';
79 32
            }
80
81 32
            return '((' . $supportQuery . ') UNION ALL (' . $mainQuery . '))';
82 16
        }
83
84 16
        // @codeCoverageIgnoreStart
85 16
        throw new \LogicException('Unreachable here');
86 16
        // @codeCoverageIgnoreEnd
87 16
    }
88
89
    /**
90
     * @return string
91
     */
92
    protected function compileSelect(Select $select)
93
    {
94
        /** @var DboSource $db */
95
        $db = $this->builder->getDataSource();
96
97
        return $db->buildStatement([
98
            'limit' => $this->compileLimit($select),
99 32
            'order' => $this->compileOrderBy($select),
100
            'conditions' => array_merge_recursive(
101 32
                $this->compileWhere($select),
102 32
                isset($this->options['conditions']) ? $this->options['conditions'] : []
103
            ),
104
            'alias' => $this->builder->alias,
105 32
            'table' => $db->fullTableName($this->builder),
106
            'fields' => [
107 32
                $db->name("{$this->builder->alias}.{$this->builder->primaryKey}"),
108 32
            ],
109 32
        ], $this->builder);
110 32
    }
111 32
112 32
    /**
113
     * @return string[]
114 32
     */
115 32
    protected function compileWhere(Select $select)
116
    {
117 32
        $conditions = [];
118
        foreach ($select->where() as $group) {
119 32
            $conditions['OR'][] = iterator_to_array($this->compileWhereGroup($group));
120
        }
121
        return $conditions;
122
    }
123
124
    /**
125
     * @return \Generator<string,string>
126 32
     */
127
    protected function compileWhereGroup(ConditionGroup $group)
128 32
    {
129 32
        foreach ($group as $condition) {
130 16
            $column = $condition->left() . ' ' . $condition->comparator();
131
            $value = $condition->right();
132 32
            yield $column => $value;
133
        }
134
    }
135
136
    /**
137
     * @param  Select|UnionAll $selectOrUnionAll
138
     * @return string[]
139 16
     */
140
    protected function compileOrderBy(SelectOrUnionAll $selectOrUnionAll)
141 16
    {
142 16
        if ($selectOrUnionAll instanceof Select) {
143 16
            $select = $selectOrUnionAll;
144 16
        }
145
        if ($selectOrUnionAll instanceof UnionAll) {
146 16
            $select = $selectOrUnionAll->mainQuery();
147
        }
148
149
        $orders = [];
150
        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...
151
            $orders[$order->column()] = $order->order();
152 32
        }
153
        return $orders;
154 32
    }
155 32
156 32
    /**
157
     * @return int
158 32
     */
159
    protected function compileLimit(Select $select)
160
    {
161
        return $select->limit()->toInteger();
162
    }
163
}
164