Completed
Pull Request — master (#375)
by Dalibor
03:13
created

DoctrineDataSource::getPlaceholder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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 Doctrine\ORM\Tools\Pagination\Paginator;
14
use Nette\Utils\Strings;
15
use Ublaboo\DataGrid\Filter;
16
use Ublaboo\DataGrid\Utils\Sorting;
17
18
/**
19
 * @method void onDataLoaded(array $result)
20
 */
21
class DoctrineDataSource extends FilterableDataSource implements IDataSource
22
{
23
24
	/**
25
	 * Event called when datagrid data is loaded.
26
	 * @var callable[]
27
	 */
28
	public $onDataLoaded;
29
30
	/**
31
	 * @var QueryBuilder
32
	 */
33
	protected $data_source;
34
35
	/**
36
	 * @var array
37
	 */
38
	protected $aggregations = [];
39
40
	/**
41
	 * @var string
42
	 */
43
	protected $primary_key;
44
45
	/**
46
	 * @var string
47
	 */
48
	protected $root_alias;
49
50
	/**
51
	 * @var int
52
	 */
53
	protected $placeholder;
54
55
56
	/**
57
	 * @param QueryBuilder $data_source
58
	 * @param string       $primary_key
59
	 */
60
	public function __construct(QueryBuilder $data_source, $primary_key)
61
	{
62
		$this->placeholder = count($data_source->getParameters());
63
		$this->data_source = $data_source;
64
		$this->primary_key = $primary_key;
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
	/**
78
	 * @param  string  $column
79
	 * @return string
80
	 */
81
	private function checkAliases($column)
82
	{
83
		if (Strings::contains($column, ".")) {
84
			return $column;
85
		}
86
87
		if (!isset($this->root_alias)) {
88
			$this->root_alias = $this->data_source->getRootAliases();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->data_source->getRootAliases() of type array is incompatible with the declared type string of property $root_alias.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
89
			$this->root_alias = current($this->root_alias);
90
		}
91
92
		return $this->root_alias.'.'.$column;
93
	}
94
95
96
	/********************************************************************************
97
	 *                          IDataSource implementation                          *
98
	 ********************************************************************************/
99
100
101
	/**
102
	 * Get count of data
103
	 * @return int
104
	 */
105
	public function getCount()
106
	{
107
		return (new Paginator($this->getQuery()))->count();
108
	}
109
110
111
	/**
112
	 * Get the data
113
	 * @return array
114
	 */
115
	public function getData()
116
	{
117
		$iterator = (new Paginator($this->getQuery()))->getIterator();
118
119
		$data = iterator_to_array($iterator);
120
121
		$this->onDataLoaded($data);
122
123
		return $data;
124
	}
125
126
127
	/**
128
	 * Filter data - get one row
129
	 * @param  array  $condition
130
	 * @return static
131
	 */
132
	public function filterOne(array $condition)
133
	{
134
		$p = $this->getPlaceholder();
135
136 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...
137
			$c = $this->checkAliases($column);
138
139
			$this->data_source->andWhere("$c = ?$p")
140
				->setParameter($p, $value);
141
		}
142
143
		return $this;
144
	}
145
146
147
	/**
148
	 * Filter by date
149
	 * @param Filter\FilterDate  $filter
150
	 */
151
	public function applyFilterDate(Filter\FilterDate $filter)
152
	{
153
		$p1 = $this->getPlaceholder();
154
		$p2 = $this->getPlaceholder();
155
156
		foreach ($filter->getCondition() as $column => $value) {
157
			$date = \DateTime::createFromFormat($filter->getPhpFormat(), $value);
158
			$c = $this->checkAliases($column);
159
160
			$this->data_source
161
				->andWhere("$c >= ?$p1")
162
				->andWhere("$c <= ?$p2")
163
				->setParameter($p1, $date->format('Y-m-d 00:00:00'))
164
				->setParameter($p2, $date->format('Y-m-d 23:59:59'));
165
		}
166
	}
167
168
169
	/**
170
	 * Filter by date range
171
	 * @param Filter\FilterDateRange  $filter
172
	 */
173
	public function applyFilterDateRange(Filter\FilterDateRange $filter)
174
	{
175
		$conditions = $filter->getCondition();
176
		$c = $this->checkAliases($filter->getColumn());
0 ignored issues
show
Bug introduced by
It seems like $filter->getColumn() targeting Ublaboo\DataGrid\Filter\Filter::getColumn() can also be of type array; however, Ublaboo\DataGrid\DataSou...aSource::checkAliases() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
177
178
		$value_from = $conditions[$filter->getColumn()]['from'];
179
		$value_to   = $conditions[$filter->getColumn()]['to'];
180
181 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...
182
			$date_from = \DateTime::createFromFormat($filter->getPhpFormat(), $value_from);
183
			$date_from->setTime(0, 0, 0);
184
185
			$p = $this->getPlaceholder();
186
187
			$this->data_source->andWhere("$c >= ?$p")->setParameter($p, $date_from->format('Y-m-d H:i:s'));
188
		}
189
190 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...
191
			$date_to = \DateTime::createFromFormat($filter->getPhpFormat(), $value_to);
192
			$date_to->setTime(23, 59, 59);
193
194
			$p = $this->getPlaceholder();
195
196
			$this->data_source->andWhere("$c <= ?$p")->setParameter($p, $date_to->format('Y-m-d H:i:s'));
197
		}
198
	}
199
200
201
	/**
202
	 * Filter by range
203
	 * @param Filter\FilterRange  $filter
204
	 */
205
	public function applyFilterRange(Filter\FilterRange $filter)
206
	{
207
		$conditions = $filter->getCondition();
208
		$c = $this->checkAliases($filter->getColumn());
0 ignored issues
show
Bug introduced by
It seems like $filter->getColumn() targeting Ublaboo\DataGrid\Filter\Filter::getColumn() can also be of type array; however, Ublaboo\DataGrid\DataSou...aSource::checkAliases() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
209
210
		$value_from = $conditions[$filter->getColumn()]['from'];
211
		$value_to   = $conditions[$filter->getColumn()]['to'];
212
213
		if ($value_from) {
214
			$p = $this->getPlaceholder();
215
			$this->data_source->andWhere("$c >= ?$p")->setParameter($p, $value_from);
216
		}
217
218
		if ($value_to) {
219
			$p = $this->getPlaceholder();
220
			$this->data_source->andWhere("$c <= ?$p")->setParameter($p, $value_to);
221
		}
222
	}
223
224
225
	/**
226
	 * Filter by keyword
227
	 * @param Filter\FilterText  $filter
228
	 */
229
	public function applyFilterText(Filter\FilterText $filter)
230
	{
231
		$condition = $filter->getCondition();
232
		$exprs = [];
233
234
		foreach ($condition as $column => $value) {
235
			$c = $this->checkAliases($column);
236
237
			if($filter->isExactSearch()){
238
				$exprs[] = $this->data_source->expr()->eq($c, $this->data_source->expr()->literal($value));
239
				continue;
240
			}
241
242 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...
243
				$words = [$value];
244
			} else {
245
				$words = explode(' ', $value);
246
			}
247
248
			foreach ($words as $word) {
249
				$exprs[] = $this->data_source->expr()->like($c, $this->data_source->expr()->literal("%$word%"));
250
			}
251
		}
252
253
		$or = call_user_func_array([$this->data_source->expr(), 'orX'], $exprs);
254
255
		$this->data_source->andWhere($or);
256
	}
257
258
259
	/**
260
	 * Filter by multi select value
261
	 * @param Filter\FilterMultiSelect  $filter
262
	 */
263
	public function applyFilterMultiSelect(Filter\FilterMultiSelect $filter)
264
	{
265
		$c = $this->checkAliases($filter->getColumn());
0 ignored issues
show
Bug introduced by
It seems like $filter->getColumn() targeting Ublaboo\DataGrid\Filter\Filter::getColumn() can also be of type array; however, Ublaboo\DataGrid\DataSou...aSource::checkAliases() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
266
		$p = $this->getPlaceholder();
267
268
		$values = $filter->getCondition()[$filter->getColumn()];
269
		$expr = $this->data_source->expr()->in($c, '?'.$p);
270
271
		$this->data_source->andWhere($expr)->setParameter($p, $values);
272
	}
273
274
275
	/**
276
	 * Filter by select value
277
	 * @param Filter\FilterSelect  $filter
278
	 */
279
	public function applyFilterSelect(Filter\FilterSelect $filter)
280
	{
281
		$p = $this->getPlaceholder();
282
283 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...
284
			$c = $this->checkAliases($column);
285
286
			$this->data_source->andWhere("$c = ?$p")
287
				->setParameter($p, $value);
288
		}
289
	}
290
291
292
	/**
293
	 * Apply limit and offset on data
294
	 * @param  int  $offset
295
	 * @param  int  $limit
296
	 * @return static
297
	 */
298
	public function limit($offset, $limit)
299
	{
300
		$this->data_source->setFirstResult($offset)->setMaxResults($limit);
301
302
		return $this;
303
	}
304
305
306
	/**
307
	 * Sort data
308
	 * @param  Sorting $sorting
309
	 * @return static
310
	 */
311 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...
312
	{
313
		if (is_callable($sorting->getSortCallback())) {
314
			call_user_func(
315
				$sorting->getSortCallback(),
316
				$this->data_source,
317
				$sorting->getSort()
318
			);
319
320
			return $this;
321
		}
322
323
		$sort = $sorting->getSort();
324
325
		if (!empty($sort)) {
326
			foreach ($sort as $column => $order) {
327
				$this->data_source->addOrderBy($this->checkAliases($column), $order);
328
			}
329
		} else {
330
			/**
331
			 * Has the statement already a order by clause?
332
			 */
333
			if (!$this->data_source->getDQLPart('orderBy')) {
334
				$this->data_source->orderBy($this->checkAliases($this->primary_key));
335
			}
336
		}
337
338
		return $this;
339
	}
340
341
342
	/**
343
	 * Get unique int value for each instance class (self)
344
	 * @return int
345
	 */
346
	public function getPlaceholder()
347
	{
348
		return $this->placeholder++;
349
	}
350
351
	/**
352
	 * @param string $aggregation_type
353
	 * @param string $column
354
	 * @return mixed
355
	 */
356
	public function addAggregationColumn($aggregation_type, $column)
357
	{
358
		$this->aggregations[$column] = $aggregation_type;
359
	}
360
361
	/**
362
	 * get aggregation row
363
	 * @return array
364
	 */
365
	public function getAggregationData()
366
	{
367
		$this->data_source->getEntityManager()->getConnection()->query('')->fetch();
368
	}
369
}
370