Completed
Pull Request — master (#315)
by Martin
03:09
created

DoctrineDataSource::setLoadedCallback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/**
4
 * @copyright   Copyright (c) 2015 ublaboo <[email protected]>
5
 * @author      Jakub Kontra <[email protected]>
6
 * @author      Pavel Janda <[email protected]>
7
 * @package     Ublaboo
8
 */
9
10
namespace Ublaboo\DataGrid\DataSource;
11
12
use Doctrine\ORM\QueryBuilder;
13
use Ublaboo\DataGrid\Filter;
14
use Nette\Utils\Callback;
15
use Nette\Utils\Strings;
16
use Doctrine;
17
use Ublaboo\DataGrid\Utils\Sorting;
18
19
class DoctrineDataSource extends FilterableDataSource implements IDataSource
20
{
21
22
	/**
23
	 * @var QueryBuilder
24
	 */
25
	protected $data_source;
26
27
	/**
28
	 * @var array
29
	 */
30
	protected $data = [];
31
32
	/**
33
	 * @var string
34
	 */
35
	protected $primary_key;
36
37
	/**
38
	 * @var int
39
	 */
40
	protected $placeholder = 0;
41
42
	/**
43
	 * @var callable
44
	 */
45
	protected $loaded_callback;
46
47
48
	/**
49
	 * @param QueryBuilder $data_source
50
	 * @param string       $primary_key
51
	 */
52
	public function __construct(QueryBuilder $data_source, $primary_key)
53
	{
54
		$this->data_source = $data_source;
55
		$this->primary_key = $primary_key;
56
	}
57
58
59
	/**
60
	 * @param callable|NULL  $callback
61
	 */
62
	public function setLoadedCallback(callable $callback = NULL)
63
	{
64
		$this->loaded_callback = $callback;
65
	}
66
67
68
	/**
69
	 * @return Doctrine\ORM\Query
70
	*/
71
	public function getQuery()
72
	{
73
		return $this->data_source->getQuery();
74
	}
75
76
77
	private function checkAliases($column)
78
	{
79
		if (Strings::contains($column, ".")) {
80
			return $column;
81
		}
82
83
		return current($this->data_source->getRootAliases()) . '.' . $column;
84
	}
85
86
87
	/********************************************************************************
88
	 *                          IDataSource implementation                          *
89
	 ********************************************************************************/
90
91
92
	/**
93
	 * Get count of data
94
	 * @return int
95
	 */
96
	public function getCount()
97
	{
98
		$paginator = new Doctrine\ORM\Tools\Pagination\Paginator($this->getQuery());
99
100
		return $paginator->count();
101
	}
102
103
104
	/**
105
	 * Get the data
106
	 * @return array
107
	 */
108
	public function getData()
109
	{
110
		$result = $this->getQuery()->getResult();
111
112
		if ($callback = $this->loaded_callback) {
113
			call_user_func_array($callback, [$result]);
114
		}
115
116
		return $result;
117
	}
118
119
120
	/**
121
	 * Filter data - get one row
122
	 * @param array $condition
123
	 * @return static
124
	 */
125
	public function filterOne(array $condition)
126
	{
127
		$p = $this->getPlaceholder();
128
129 View Code Duplication
		foreach ($condition as $column => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
130
			$c = $this->checkAliases($column);
131
132
			$this->data_source->andWhere("$c = ?$p")
133
				->setParameter($p, $value);
134
		}
135
136
		return $this;
137
	}
138
139
140
	/**
141
	 * Filter by date
142
	 * @param  Filter\FilterDate $filter
143
	 * @return static
144
	 */
145
	public function applyFilterDate(Filter\FilterDate $filter)
146
	{
147
		$p1 = $this->getPlaceholder();
148
		$p2 = $this->getPlaceholder();
149
150
		foreach ($filter->getCondition() as $column => $value) {
151
			$date = \DateTime::createFromFormat($filter->getPhpFormat(), $value);
152
			$c = $this->checkAliases($column);
153
154
			$this->data_source
155
				->andWhere("$c >= ?$p1")
156
				->andWhere("$c <= ?$p2")
157
				->setParameter($p1, $date->format('Y-m-d 00:00:00'))
158
				->setParameter($p2, $date->format('Y-m-d 23:59:59'));
159
		}
160
161
		return $this;
162
	}
163
164
165
	/**
166
	 * Filter by date range
167
	 * @param  Filter\FilterDateRange $filter
168
	 * @return void
169
	 */
170
	public function applyFilterDateRange(Filter\FilterDateRange $filter)
171
	{
172
		$conditions = $filter->getCondition();
173
		$c = $this->checkAliases($filter->getColumn());
174
175
		$value_from = $conditions[$filter->getColumn()]['from'];
176
		$value_to   = $conditions[$filter->getColumn()]['to'];
177
178 View Code Duplication
		if ($value_from) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
179
			$date_from = \DateTime::createFromFormat($filter->getPhpFormat(), $value_from);
180
			$date_from->setTime(0, 0, 0);
181
182
			$p = $this->getPlaceholder();
183
184
			$this->data_source->andWhere("$c >= ?$p")->setParameter($p, $date_from->format('Y-m-d H:i:s'));
185
		}
186
187 View Code Duplication
		if ($value_to) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
188
			$date_to = \DateTime::createFromFormat($filter->getPhpFormat(), $value_to);
189
			$date_to->setTime(23, 59, 59);
190
191
			$p = $this->getPlaceholder();
192
193
			$this->data_source->andWhere("$c <= ?$p")->setParameter($p, $date_to->format('Y-m-d H:i:s'));
194
		}
195
	}
196
197
198
	/**
199
	 * Filter by range
200
	 * @param  Filter\FilterRange $filter
201
	 * @return void
202
	 */
203
	public function applyFilterRange(Filter\FilterRange $filter)
204
	{
205
		$conditions = $filter->getCondition();
206
		$c = $this->checkAliases($filter->getColumn());
207
208
		$value_from = $conditions[$filter->getColumn()]['from'];
209
		$value_to   = $conditions[$filter->getColumn()]['to'];
210
211
		if ($value_from) {
212
			$p = $this->getPlaceholder();
213
			$this->data_source->andWhere("$c >= ?$p")->setParameter($p, $value_from);
214
		}
215
216
		if ($value_to) {
217
			$p = $this->getPlaceholder();
218
			$this->data_source->andWhere("$c <= ?$p")->setParameter($p, $value_to);
219
		}
220
	}
221
222
223
	/**
224
	 * Filter by keyword
225
	 * @param  Filter\FilterText $filter
226
	 * @return void
227
	 */
228
	public function applyFilterText(Filter\FilterText $filter)
229
	{
230
		$condition = $filter->getCondition();
231
		$exprs = [];
232
233
		foreach ($condition as $column => $value) {
234 View Code Duplication
			if ($filter->hasSplitWordsSearch() === FALSE) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
235
				$words = [$value];
236
			} else {
237
				$words = explode(' ', $value);
238
			}
239
240
			$c = $this->checkAliases($column);
241
242
			foreach ($words as $word) {
243
				$exprs[] = $this->data_source->expr()->like($c, $this->data_source->expr()->literal("%$word%"));
244
			}
245
		}
246
247
		$or = call_user_func_array([$this->data_source->expr(), 'orX'], $exprs);
248
249
		$this->data_source->andWhere($or);
250
	}
251
252
253
	/**
254
	 * Filter by multi select value
255
	 * @param  Filter\FilterMultiSelect $filter
256
	 * @return void
257
	 */
258
	public function applyFilterMultiSelect(Filter\FilterMultiSelect $filter)
259
	{
260
		$c = $this->checkAliases($filter->getColumn());
261
		$p = $this->getPlaceholder();
262
263
		$values = $filter->getCondition()[$filter->getColumn()];
264
		$expr = $this->data_source->expr()->in($c, '?'.$p);
265
266
		$this->data_source->andWhere($expr)->setParameter($p, $values);
267
	}
268
269
270
	/**
271
	 * Filter by select value
272
	 * @param  Filter\FilterSelect $filter
273
	 * @return void
274
	 */
275
	public function applyFilterSelect(Filter\FilterSelect $filter)
276
	{
277
		$p = $this->getPlaceholder();
278
279 View Code Duplication
		foreach ($filter->getCondition() as $column => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
280
			$c = $this->checkAliases($column);
281
282
			$this->data_source->andWhere("$c = ?$p")
283
				->setParameter($p, $value);
284
		}
285
	}
286
287
288
	/**
289
	 * Apply limit and offset on data
290
	 * @param int $offset
291
	 * @param int $limit
292
	 * @return static
293
	 */
294
	public function limit($offset, $limit)
295
	{
296
		$this->data_source->setFirstResult($offset)->setMaxResults($limit);
297
298
		return $this;
299
	}
300
301
302
	/**
303
	 * Sort data
304
	 * @param  Sorting $sorting
305
	 * @return static
306
	 */
307 View Code Duplication
	public function sort(Sorting $sorting)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
308
	{
309
		if (is_callable($sorting->getSortCallback())) {
310
			call_user_func(
311
				$sorting->getSortCallback(),
312
				$this->data_source,
313
				$sorting->getSort()
314
			);
315
316
			return $this;
317
		}
318
319
		$sort = $sorting->getSort();
320
321
		if (!empty($sort)) {
322
			foreach ($sort as $column => $order) {
323
				$this->data_source->addOrderBy($this->checkAliases($column), $order);
324
			}
325
		} else {
326
			/**
327
			 * Has the statement already a order by clause?
328
			 */
329
			if (!$this->data_source->getDQLPart('orderBy')) {
330
				$this->data_source->orderBy($this->checkAliases($this->primary_key));
331
			}
332
		}
333
334
		return $this;
335
	}
336
337
338
	/**
339
	 * Get unique int value for each instance class (self)
340
	 * @return int
341
	 */
342
	public function getPlaceholder()
343
	{
344
		$this->placeholder++;
345
346
		return $this->placeholder;
347
	}
348
349
}
350