Completed
Push — master ( 91ef18...a6f36a )
by Pavel
03:04
created

DoctrineDataSource   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 280
Duplicated Lines 16.07 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 14
Bugs 2 Features 7
Metric Value
wmc 28
c 14
b 2
f 7
lcom 1
cbo 7
dl 45
loc 280
rs 10

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getQuery() 0 4 1
A checkAliases() 0 8 2
A getCount() 0 7 1
A getData() 0 7 2
A filterOne() 6 13 2
A applyFilterDate() 0 18 2
B applyFilterDateRange() 16 26 3
A applyFilterRange() 0 18 3
A applyFilterText() 0 18 3
A applyFilterSelect() 6 11 2
A limit() 0 6 1
A sort() 17 17 4
A getPlaceholder() 0 6 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
	Ublaboo\DataGrid\Filter,
14
	Nette\Utils\Callback,
15
	Nette\Utils\Strings,
16
	Doctrine;
17
18
class DoctrineDataSource extends FilterableDataSource implements IDataSource
19
{
20
21
	/**
22
	 * @var QueryBuilder
23
	 */
24
	protected $data_source;
25
26
	/**
27
	 * @var array
28
	 */
29
	protected $data = [];
30
31
	/**
32
	 * @var string
33
	 */
34
	protected $primary_key;
35
36
	/**
37
	 * @var int
38
	 */
39
	protected $placeholder = 0;
40
41
42
	/**
43
	 * @param QueryBuilder $data_source
44
	 * @param string       $primary_key
45
	 */
46
	public function __construct(QueryBuilder $data_source, $primary_key)
47
	{
48
		$this->data_source = $data_source;
49
		$this->primary_key = $primary_key;
50
	}
51
52
53
	/**
54
	 * @return Doctrine\ORM\Query
55
	*/
56
	public function getQuery()
57
	{
58
		return $this->data_source->getQuery();
59
	}
60
61
62
	private function checkAliases($column)
63
	{
64
		if (Strings::contains($column, ".")) {
65
			return $column;
66
		}
67
68
		return current($this->data_source->getRootAliases()) . '.' . $column;
69
	}
70
71
72
	/********************************************************************************
73
	 *                          IDataSource implementation                          *
74
	 ********************************************************************************/
75
76
77
	/**
78
	 * Get count of data
79
	 * @return int
80
	 */
81
	public function getCount()
82
	{
83
		$paginator = new Doctrine\ORM\Tools\Pagination\Paginator($this->getQuery());
84
		$count = count($paginator);
85
86
		return $count;
87
	}
88
89
	/**
90
	 * Get the data
91
	 * @return array
92
	 */
93
	public function getData()
94
	{
95
		/**
96
		 * Paginator is better if the query uses ManyToMany associations
97
		 */
98
		return $this->data ?: $this->data_source->getQuery()->getResult();
99
	}
100
101
102
	/**
103
	 * Filter data - get one row
104
	 * @param array $condition
105
	 * @return static
106
	 */
107
	public function filterOne(array $condition)
108
	{
109
		$p = $this->getPlaceholder();
110
111 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...
112
			$c = $this->checkAliases($column);
113
114
			$this->data_source->andWhere("$c = ?$p")
115
				->setParameter($p, $value);
116
		}
117
118
		return $this;
119
	}
120
121
122
	/**
123
	 * Filter by date
124
	 * @param  Filter\FilterDate $filter
125
	 * @return static
126
	 */
127
	public function applyFilterDate(Filter\FilterDate $filter)
128
	{
129
		$p1 = $this->getPlaceholder();
130
		$p2 = $this->getPlaceholder();
131
132
		foreach ($filter->getCondition() as $column => $value) {
133
			$date = \DateTime::createFromFormat($filter->getPhpFormat(), $value);
134
			$c = $this->checkAliases($column);
135
136
			$this->data_source
137
				->andWhere("$c >= ?$p1")
138
				->andWhere("$c <= ?$p2")
139
				->setParameter($p1, $date->format('Y-m-d 00:00:00'))
140
				->setParameter($p2, $date->format('Y-m-d 23:59:59'));
141
		}
142
143
		return $this;
144
	}
145
146
147
	/**
148
	 * Filter by date range
149
	 * @param  Filter\FilterDateRange $filter
150
	 * @return void
151
	 */
152
	public function applyFilterDateRange(Filter\FilterDateRange $filter)
153
	{
154
		$conditions = $filter->getCondition();
155
		$c = $this->checkAliases($filter->getColumn());
156
157
		$value_from = $conditions[$filter->getColumn()]['from'];
158
		$value_to   = $conditions[$filter->getColumn()]['to'];
159
160 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...
161
			$date_from = \DateTime::createFromFormat($filter->getPhpFormat(), $value_from);
162
			$date_from->setTime(0, 0, 0);
163
164
			$p = $this->getPlaceholder();
165
166
			$this->data_source->andWhere("$c >= ?$p")->setParameter($p, $date_from->format('Y-m-d H:i:s'));
167
		}
168
169 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...
170
			$date_to = \DateTime::createFromFormat($filter->getPhpFormat(), $value_to);
171
			$date_to->setTime(23, 59, 59);
172
173
			$p = $this->getPlaceholder();
174
175
			$this->data_source->andWhere("$c <= ?$p")->setParameter($p, $date_to->format('Y-m-d H:i:s'));
176
		}
177
	}
178
179
180
	/**
181
	 * Filter by range
182
	 * @param  Filter\FilterRange $filter
183
	 * @return void
184
	 */
185
	public function applyFilterRange(Filter\FilterRange $filter)
186
	{
187
		$conditions = $filter->getCondition();
188
		$c = $this->checkAliases($filter->getColumn());
189
190
		$value_from = $conditions[$filter->getColumn()]['from'];
191
		$value_to   = $conditions[$filter->getColumn()]['to'];
192
193
		if ($value_from) {
194
			$p = $this->getPlaceholder();
195
			$this->data_source->andWhere("$c >= ?$p")->setParameter($p, $value_from);
196
		}
197
198
		if ($value_to) {
199
			$p = $this->getPlaceholder();
200
			$this->data_source->andWhere("$c <= ?$p")->setParameter($p, $value_to);
201
		}
202
	}
203
204
205
	/**
206
	 * Filter by keyword
207
	 * @param  Filter\FilterText $filter
208
	 * @return void
209
	 */
210
	public function applyFilterText(Filter\FilterText $filter)
211
	{
212
		$condition = $filter->getCondition();
213
		$exprs = [];
214
215
		foreach ($condition as $column => $value) {
216
			$words = explode(' ', $value);
217
			$c = $this->checkAliases($column);
218
219
			foreach ($words as $word) {
220
				$exprs[] = $this->data_source->expr()->like($c, $this->data_source->expr()->literal("%$word%"));
221
			}
222
		}
223
224
		$or = call_user_func_array([$this->data_source->expr(), 'orX'], $exprs);
225
226
		$this->data_source->andWhere($or);
227
	}
228
229
230
	/**
231
	 * Filter by select value
232
	 * @param  Filter\FilterSelect $filter
233
	 * @return void
234
	 */
235
	public function applyFilterSelect(Filter\FilterSelect $filter)
236
	{
237
		$p = $this->getPlaceholder();
238
239 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...
240
			$c = $this->checkAliases($column);
241
242
			$this->data_source->andWhere("$c = ?$p")
243
				->setParameter($p, $value);
244
		}
245
	}
246
247
248
	/**
249
	 * Apply limit and offet on data
250
	 * @param int $offset
251
	 * @param int $limit
252
	 * @return static
253
	 */
254
	public function limit($offset, $limit)
255
	{
256
		$this->data_source->setFirstResult($offset)->setMaxResults($limit);
257
258
		return $this;
259
	}
260
261
262
	/**
263
	 * Order data
264
	 * @param  array  $sorting
265
	 * @return static
266
	 */
267 View Code Duplication
	public function sort(array $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...
268
	{
269
		if (!empty($sorting)) {
270
			foreach ($sorting as $column => $sort) {
271
				$this->data_source->addOrderBy($this->checkAliases($column), $sort);
272
			}
273
		} else {
274
			/**
275
			 * Has the statement already a order by clause?
276
			 */
277
			if (!$this->data_source->getDQLPart('orderBy')) {
278
				$this->data_source->orderBy($this->checkAliases($this->primary_key));
279
			}
280
		}
281
282
		return $this;
283
	}
284
285
286
	/**
287
	 * Get unique int value for each instance class (self)
288
	 * @return int
289
	 */
290
	public function getPlaceholder()
291
	{
292
		$this->placeholder++;
293
294
		return $this->placeholder;
295
	}
296
297
}
298