1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of vaibhavpandeyvpz/doctrine-datatables package. |
5
|
|
|
* |
6
|
|
|
* (c) Vaibhav Pandey <[email protected]> |
7
|
|
|
* |
8
|
|
|
* This source file is subject to the MIT license that is bundled |
9
|
|
|
* with this source code in the file LICENSE.md. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Doctrine\DataTables; |
13
|
|
|
|
14
|
|
|
use Doctrine\DBAL\Query\QueryBuilder; |
15
|
|
|
use Doctrine\ORM\QueryBuilder as ORMQueryBuilder; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Class Builder |
19
|
|
|
* @package Doctrine\DataTables |
20
|
|
|
*/ |
21
|
|
|
class Builder |
22
|
|
|
{ |
23
|
|
|
/** |
24
|
|
|
* @var array |
25
|
|
|
*/ |
26
|
|
|
protected $columnAliases = array(); |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var string |
30
|
|
|
*/ |
31
|
|
|
protected $columnField = 'name'; // or 'data' |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var string |
35
|
|
|
*/ |
36
|
|
|
protected $indexColumn = '*'; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var QueryBuilder|ORMQueryBuilder |
40
|
|
|
*/ |
41
|
|
|
protected $queryBuilder; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var array |
45
|
|
|
*/ |
46
|
|
|
protected $requestParams; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @return array |
50
|
|
|
*/ |
51
|
|
|
public function getData() |
52
|
|
|
{ |
53
|
|
|
$query = $this->getFilteredQuery(); |
54
|
|
|
$columns = &$this->requestParams['columns']; |
55
|
|
|
// Order |
56
|
|
|
if (array_key_exists('order', $this->requestParams)) { |
57
|
|
|
$order = &$this->requestParams['order']; |
58
|
|
|
foreach ($order as $sort) { |
59
|
|
|
$column = &$columns[intval($sort['column'])]; |
60
|
|
|
if (array_key_exists($column[$this->columnField], $this->columnAliases)) { |
61
|
|
|
$column[$this->columnField] = $this->columnAliases[$column[$this->columnField]]; |
62
|
|
|
} |
63
|
|
|
$query->addOrderBy($column[$this->columnField], $sort['dir']); |
64
|
|
|
} |
65
|
|
|
} |
66
|
|
|
// Offset |
67
|
|
|
if (array_key_exists('start', $this->requestParams)) { |
68
|
|
|
$query->setFirstResult(intval($this->requestParams['start'])); |
69
|
|
|
} |
70
|
|
|
// Limit |
71
|
|
|
if (array_key_exists('length', $this->requestParams)) { |
72
|
|
|
$length = intval($this->requestParams['length']); |
73
|
|
|
if ($length > 0) { |
74
|
|
|
$query->setMaxResults($length); |
75
|
|
|
} |
76
|
|
|
} |
77
|
|
|
// Fetch |
78
|
|
|
return $query instanceof ORMQueryBuilder ? |
79
|
|
|
$query->getQuery()->getArrayResult() : $query->execute()->fetchAll(); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @return QueryBuilder|ORMQueryBuilder |
84
|
|
|
*/ |
85
|
|
|
public function getFilteredQuery() |
86
|
|
|
{ |
87
|
|
|
$query = clone $this->queryBuilder; |
88
|
|
|
$columns = &$this->requestParams['columns']; |
89
|
|
|
$c = count($columns); |
90
|
|
|
// Search |
91
|
|
|
if (array_key_exists('search', $this->requestParams)) { |
92
|
|
|
if ($value = trim($this->requestParams['search']['value'])) { |
93
|
|
|
$orX = $query->expr()->orX(); |
94
|
|
|
for ($i = 0; $i < $c; $i++) { |
95
|
|
|
$column = &$columns[$i]; |
96
|
|
|
if ($column['searchable'] == 'true') { |
97
|
|
|
if (array_key_exists($column[$this->columnField], $this->columnAliases)) { |
98
|
|
|
$column[$this->columnField] = $this->columnAliases[$column[$this->columnField]]; |
99
|
|
|
} |
100
|
|
|
$orX->add($query->expr()->like($column[$this->columnField], ':search')); |
101
|
|
|
} |
102
|
|
|
} |
103
|
|
|
if ($orX->count() >= 1) { |
104
|
|
|
$query->andWhere($orX) |
105
|
|
|
->setParameter('search', "%{$value}%"); |
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
// Filter |
110
|
|
|
for ($i = 0; $i < $c; $i++) { |
111
|
|
|
$column = &$columns[$i]; |
112
|
|
|
$andX = $query->expr()->andX(); |
113
|
|
|
if (($column['searchable'] == 'true') && ($value = trim($column['search']['value']))) { |
114
|
|
|
if (array_key_exists($column[$this->columnField], $this->columnAliases)) { |
115
|
|
|
$column[$this->columnField] = $this->columnAliases[$column[$this->columnField]]; |
116
|
|
|
} |
117
|
|
|
$operator = preg_match('~^\[(?<operator>[=!%<>]+)\].*$~', $value, $matches) ? $matches['operator'] : '='; |
118
|
|
|
switch ($operator) { |
119
|
|
|
case '!=': // Not equals; usage: [!=]search_term |
120
|
|
|
$andX->add($query->expr()->neq($column[$this->columnField], ":filter_{$i}")); |
121
|
|
|
break; |
122
|
|
|
case '%': // Like; usage: [%]search_term |
123
|
|
|
$andX->add($query->expr()->like($column[$this->columnField], ":filter_{$i}")); |
124
|
|
|
$value = "%{$value}%"; |
125
|
|
|
break; |
126
|
|
|
case '<': // Greater than; usage: [<]search_term |
127
|
|
|
$andX->add($query->expr()->gt($column[$this->columnField], ":filter_{$i}")); |
128
|
|
|
break; |
129
|
|
|
case '>': // Less than; usage: [>]search_term |
130
|
|
|
$andX->add($query->expr()->lt($column[$this->columnField], ":filter_{$i}")); |
131
|
|
|
break; |
132
|
|
|
case '=': // Equals (default); usage: [=]search_term |
|
|
|
|
133
|
|
|
default: |
134
|
|
|
$andX->add($query->expr()->eq($column[$this->columnField], ":filter_{$i}")); |
135
|
|
|
break; |
136
|
|
|
} |
137
|
|
|
$query->setParameter("filter_{$i}", $value); |
138
|
|
|
} |
139
|
|
|
if ($andX->count() >= 1) { |
140
|
|
|
$query->andWhere($andX); |
141
|
|
|
} |
142
|
|
|
} |
143
|
|
|
// Done |
144
|
|
|
return $query; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* @return int |
149
|
|
|
*/ |
150
|
|
|
public function getRecordsFiltered() |
151
|
|
|
{ |
152
|
|
|
$query = $this->getFilteredQuery(); |
153
|
|
|
if ($query instanceof ORMQueryBuilder) { |
154
|
|
|
return $query->resetDQLPart('select') |
155
|
|
|
->select("COUNT({$this->indexColumn})") |
156
|
|
|
->getQuery() |
157
|
|
|
->getSingleScalarResult(); |
158
|
|
|
} else { |
159
|
|
|
return $query->resetQueryPart('select') |
160
|
|
|
->select("COUNT({$this->indexColumn})") |
161
|
|
|
->execute() |
162
|
|
|
->fetchColumn(0); |
163
|
|
|
} |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* @return int |
168
|
|
|
*/ |
169
|
|
|
public function getRecordsTotal() |
170
|
|
|
{ |
171
|
|
|
$query = clone $this->queryBuilder; |
172
|
|
|
if ($query instanceof ORMQueryBuilder) { |
173
|
|
|
return $query->resetDQLPart('select') |
174
|
|
|
->select("COUNT({$this->indexColumn})") |
175
|
|
|
->getQuery() |
176
|
|
|
->getSingleScalarResult(); |
177
|
|
|
} else { |
178
|
|
|
return $query->resetQueryPart('select') |
179
|
|
|
->select("COUNT({$this->indexColumn})") |
180
|
|
|
->execute() |
181
|
|
|
->fetchColumn(0); |
182
|
|
|
} |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* @return array |
187
|
|
|
*/ |
188
|
|
|
public function getResponse() |
189
|
|
|
{ |
190
|
|
|
return array( |
191
|
|
|
'data' => $this->getData(), |
192
|
|
|
'draw' => $this->requestParams['draw'], |
193
|
|
|
'recordsFiltered' => $this->getRecordsFiltered(), |
194
|
|
|
'recordsTotal' => $this->getRecordsTotal(), |
195
|
|
|
); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @param string $indexColumn |
200
|
|
|
* @return static |
201
|
|
|
*/ |
202
|
|
|
public function withIndexColumn($indexColumn) |
203
|
|
|
{ |
204
|
|
|
$this->indexColumn = $indexColumn; |
205
|
|
|
return $this; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* @param array $columnAliases |
210
|
|
|
* @return static |
211
|
|
|
*/ |
212
|
|
|
public function withColumnAliases($columnAliases) |
213
|
|
|
{ |
214
|
|
|
$this->columnAliases = $columnAliases; |
215
|
|
|
return $this; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/** |
219
|
|
|
* @param array $columnField |
220
|
|
|
* @return static |
221
|
|
|
*/ |
222
|
|
|
public function withColumnField($columnField) |
223
|
|
|
{ |
224
|
|
|
$this->columnField = $columnField; |
|
|
|
|
225
|
|
|
return $this; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* @param QueryBuilder|ORMQueryBuilder $queryBuilder |
230
|
|
|
* @return static |
231
|
|
|
*/ |
232
|
|
|
public function withQueryBuilder($queryBuilder) |
233
|
|
|
{ |
234
|
|
|
$this->queryBuilder = $queryBuilder; |
235
|
|
|
return $this; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* @param array $requestParams |
240
|
|
|
* @return static |
241
|
|
|
*/ |
242
|
|
|
public function withRequestParams($requestParams) |
243
|
|
|
{ |
244
|
|
|
$this->requestParams = $requestParams; |
245
|
|
|
return $this; |
246
|
|
|
} |
247
|
|
|
} |
248
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.