Test Failed
Push — master ( ce96ba...918ead )
by Joao
01:53
created

src/Query.php (1 issue)

1
<?php
2
3
namespace ByJG\MicroOrm;
4
5
use ByJG\AnyDataset\Db\DbDriverInterface;
6
use ByJG\MicroOrm\Exception\InvalidArgumentException;
7
use ByJG\Serializer\BinderObject;
8
9
class Query
10
{
11
    protected $fields = [];
12
    protected $table = "";
13
    protected $where = [];
14
    protected $groupBy = [];
15
    protected $orderBy = [];
16
    protected $join = [];
17
    protected $limitStart = null;
18
    protected $limitEnd = null;
19
    protected $top = null;
20
21
    protected $forUpdate = false;
22
23
    public static function getInstance()
24
    {
25
        return new Query();
26
    }
27
28 6
    /**
29
     * Example:
30 6
     *   $query->fields(['name', 'price']);
31
     *
32
     * @param array $fields
33
     * @return $this
34
     * @throws \ByJG\Serializer\Exception\InvalidArgumentException
35
     */
36
    public function fields(array $fields)
37
    {
38
        foreach ($fields as $field) {
39
            if ($field instanceof Mapper) {
40
                $this->addFieldFromMapper($field);
41 5
                continue;
42
            }
43 5
            $this->fields[] = $field;
44 5
        }
45 1
46 1
        return $this;
47
    }
48 4
49 5
    /**
50
     * @param \ByJG\MicroOrm\Mapper $mapper
51 5
     * @throws \ByJG\Serializer\Exception\InvalidArgumentException
52
     */
53
    private function addFieldFromMapper(Mapper $mapper)
54
    {
55
        $entityClass = $mapper->getEntity();
56
        $entity = new $entityClass();
57
        $serialized = BinderObject::toArrayFrom($entity);
58 1
59
        foreach (array_keys($serialized) as $fieldName) {
60 1
            $mapField = $mapper->getFieldMap($fieldName, Mapper::FIELDMAP_FIELD);
61 1
            if (empty($mapField)) {
62 1
                $mapField = $fieldName;
63
            }
64 1
65 1
            $alias = $mapper->getFieldAlias($mapField);
66 1
            if (!empty($alias)) {
67 1
                $alias = ' as ' . $alias;
0 ignored issues
show
Are you sure $alias of type array|mixed can be used in concatenation? ( Ignorable by Annotation )

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

67
                $alias = ' as ' . /** @scrutinizer ignore-type */ $alias;
Loading history...
68 1
            }
69
70 1
            $this->fields[] = $mapper->getTable() . '.' . $mapField . $alias;
71 1
        }
72 1
    }
73 1
74
    /**
75 1
     * Example
76 1
     *    $query->table('product');
77 1
     *
78
     * @param string $table
79
     * @return $this
80
     */
81
    public function table($table)
82
    {
83
        $this->table = $table;
84
85
        return $this;
86 24
    }
87
88 24
    /**
89
     * Example:
90 24
     *    $query->join('sales', 'product.id = sales.id');
91
     *
92
     * @param string $table
93
     * @param string $filter
94
     * @return $this
95
     */
96
    public function join($table, $filter)
97
    {
98
        $this->join[] = [ 'table'=>$table, 'filter'=>$filter, 'type' => 'INNER'];
99
        return $this;
100
    }
101 1
102
    /**
103 1
     * Example:
104 1
     *    $query->join('sales', 'product.id = sales.id');
105
     *
106
     * @param string $table
107
     * @param string $filter
108
     * @return $this
109
     */
110
    public function leftJoin($table, $filter)
111
    {
112
        $this->join[] = [ 'table'=>$table, 'filter'=>$filter, 'type' => 'LEFT'];
113
        return $this;
114
    }
115 1
116
    /**
117 1
     * Example:
118 1
     *    $query->filter('price > [[amount]]', [ 'amount' => 1000] );
119
     *
120
     * @param string $filter
121
     * @param array $params
122
     * @return $this
123
     */
124
    public function where($filter, array $params = [])
125
    {
126
        $this->where[] = [ 'filter' => $filter, 'params' => $params  ];
127
        return $this;
128
    }
129 22
130
    /**
131 22
     * Example:
132 22
     *    $query->groupBy(['name']);
133
     *
134
     * @param array $fields
135
     * @return $this
136
     */
137
    public function groupBy(array $fields)
138
    {
139
        $this->groupBy = array_merge($this->groupBy, $fields);
140
    
141
        return $this;
142 1
    }
143
144 1
    /**
145
     * Example:
146 1
     *     $query->orderBy(['price desc']);
147
     *
148
     * @param array $fields
149
     * @return $this
150
     */
151
    public function orderBy(array $fields)
152
    {
153
        $this->orderBy = array_merge($this->orderBy, $fields);
154
155
        return $this;
156 4
    }
157
158 4
    public function forUpdate()
159
    {
160 4
        $this->forUpdate = true;
161
        
162
        return $this;
163
    }
164
165
    /**
166
     * @param $start
167
     * @param $end
168
     * @return $this
169
     * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException
170 1
     */
171
    public function limit($start, $end)
172 1
    {
173
        if (!is_null($this->top)) {
174
            throw new InvalidArgumentException('You cannot mix TOP and LIMIT');
175 1
        }
176 1
        $this->limitStart = $start;
177 1
        $this->limitEnd = $end;
178
        return $this;
179
    }
180 1
181
    /**
182 1
     * @param $top
183
     * @return $this
184
     * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException
185 1
     */
186 1
    public function top($top)
187
    {
188
        if (!is_null($this->limitStart)) {
189 24
            throw new InvalidArgumentException('You cannot mix TOP and LIMIT');
190
        }
191 24
        $this->top = $top;
192 20
        return $this;
193
    }
194
195 5
    protected function getFields()
196
    {
197
        if (empty($this->fields)) {
198 24
            return ' * ';
199
        }
200 24
201 24
        return ' ' . implode(', ', $this->fields) . ' ';
202 2
    }
203 24
    
204 24
    protected function getJoin()
205
    {
206
        $joinStr = $this->table;
207 24
        foreach ($this->join as $item) {
208
            $joinStr .= ' ' . $item['type'] . ' JOIN ' . $item['table'] . ' ON ' . $item['filter'];
209 24
        }
210 24
        return $joinStr;
211
    }
212 24
    
213 22
    protected function getWhere()
214 22
    {
215 24
        $whereStr = [];
216
        $params = [];
217 24
218 3
        foreach ($this->where as $item) {
219
            $whereStr[] = $item['filter'];
220
            $params = array_merge($params, $item['params']);
221 22
        }
222
        
223
        if (empty($whereStr)) {
224
            return null;
225
        }
226
        
227
        return [ implode(' AND ', $whereStr), $params ];
228 24
    }
229
230
    /**
231 24
     * @param \ByJG\AnyDataset\Db\DbDriverInterface|null $dbDriver
232 24
     * @return array
233
     * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException
234 24
     */
235 24
    public function build(DbDriverInterface $dbDriver = null)
236 24
    {
237 22
        $sql = "SELECT " .
238 22
            $this->getFields() .
239 22
            "FROM " . $this->getJoin();
240
        
241 24
        $whereStr = $this->getWhere();
242
        $params = null;
243 24
        if (!is_null($whereStr)) {
244
            $sql .= ' WHERE ' . $whereStr[0];
245 24
            $params = $whereStr[1];
246
        }
247 24
248
        $sql .= $this->addGroupBy();
249 24
250
        $sql .= $this->addOrderBy();
251 24
252
        $sql = $this->addforUpdate($dbDriver, $sql);
253 24
254
        $sql = $this->addTop($dbDriver, $sql);
255
256 24
        $sql = $this->addLimit($dbDriver, $sql);
257
258 24
        $sql = ORMHelper::processLiteral($sql, $params);
259 21
260
        return [ 'sql' => $sql, 'params' => $params ];
261 4
    }
262
263
    private function addOrderBy()
264 24
    {
265
        if (empty($this->orderBy)) {
266 24
            return "";
267 24
        }
268
        return ' ORDER BY ' . implode(', ', $this->orderBy);
269 1
    }
270
271
    private function addGroupBy()
272
    {
273
        if (empty($this->groupBy)) {
274
            return "";
275
        }
276
        return ' GROUP BY ' . implode(', ', $this->groupBy);
277 24
    }
278
279 24
    /**
280 24
     * @param DbDriverInterface $dbDriver
281
     * @param string $sql
282
     * @return string
283
     * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException
284
     */
285
    private function addforUpdate($dbDriver, $sql)
286
    {
287
        if (empty($this->forUpdate)) {
288
            return $sql;
289
        }
290
291
        if (is_null($dbDriver)) {
292
            throw new InvalidArgumentException('To get FOR UPDATE working you have to pass the DbDriver');
293
        }
294
295 24
        return $dbDriver->getDbHelper()->forUpdate($sql);
296
    }
297 24
298 23
    /**
299
     * @param DbDriverInterface $dbDriver
300
     * @param string $sql
301 1
     * @return string
302
     * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException
303
     */
304
    private function addTop($dbDriver, $sql)
305 1
    {
306
        if (empty($this->top)) {
307
            return $sql;
308
        }
309
310
        if (is_null($dbDriver)) {
311
            throw new InvalidArgumentException('To get Limit and Top working you have to pass the DbDriver');
312
        }
313 24
314
        return $dbDriver->getDbHelper()->top($sql, $this->top);
315 24
    }
316 23
317
    /**
318
     * @param DbDriverInterface $dbDriver
319 1
     * @param string $sql
320
     * @return string
321
     * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException
322
     */
323 1
    private function addLimit($dbDriver, $sql)
324
    {
325
        if (empty($this->limitStart) && ($this->limitStart !== 0)) {
326
            return $sql;
327
        }
328
329
        if (is_null($dbDriver)) {
330
            throw new InvalidArgumentException('To get Limit and Top working you have to pass the DbDriver');
331
        }
332
333
        return $dbDriver->getDbHelper()->limit($sql, $this->limitStart, $this->limitEnd);
334
    }
335
}
336