Completed
Pull Request — master (#375)
by Dalibor
02:34
created

NetteDatabaseTableDataSource   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 320
Duplicated Lines 25 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
wmc 34
lcom 1
cbo 11
dl 80
loc 320
rs 9.2
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getCount() 0 12 3
A getData() 0 4 2
A filterOne() 0 6 1
A applyFilterDate() 8 8 1
A applyFilterDateRange() 21 21 3
A applyFilterRange() 15 15 3
B applyFilterText() 5 46 6
B applyFilterMultiSelect() 0 27 4
A applyFilterSelect() 0 4 1
A limit() 0 6 1
B sort() 31 31 5
A addAggregationColumn() 0 4 1
A getAggregationData() 0 9 2

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      Pavel Janda <[email protected]>
6
 * @package     Ublaboo
7
 */
8
9
namespace Ublaboo\DataGrid\DataSource;
10
11
use Nette\Database\Table\Selection;
12
use Ublaboo\DataGrid\Filter;
13
use Ublaboo\DataGrid\Utils\DateTimeHelper;
14
use Ublaboo\DataGrid\Utils\Sorting;
15
16
class NetteDatabaseTableDataSource extends FilterableDataSource implements IDataSource
17
{
18
19
	/**
20
	 * @var Selection
21
	 */
22
	protected $data_source;
23
24
	/**
25
	 * @var array
26
	 */
27
	protected  $aggregations =[];
28
29
	/**
30
	 * @var array
31
	 */
32
	protected $data = [];
33
34
	/**
35
	 * @var string
36
	 */
37
	protected $primary_key;
38
39
40
	/**
41
	 * @param Selection $data_source
42
	 * @param string $primary_key
43
	 */
44
	public function __construct(Selection $data_source, $primary_key)
45
	{
46
		$this->data_source = $data_source;
47
48
		$this->primary_key = $primary_key;
49
	}
50
51
52
	/********************************************************************************
53
	 *                          IDataSource implementation                          *
54
	 ********************************************************************************/
55
56
57
	/**
58
	 * Get count of data
59
	 * @return int
60
	 */
61
	public function getCount()
62
	{
63
		try {
64
			$primary = $this->data_source->getPrimary();
65
		} catch (\LogicException $e) {
66
			return $this->data_source->count('*');
67
		}
68
69
		return $this->data_source->count(
70
			$this->data_source->getName() . '.' . (is_array($primary) ? reset($primary) : $primary)
71
		);
72
	}
73
74
75
	/**
76
	 * Get the data
77
	 * @return array
78
	 */
79
	public function getData()
80
	{
81
		return $this->data ?: $this->data_source->fetchAll();
82
	}
83
84
85
	/**
86
	 * Filter data - get one row
87
	 * @param array $condition
88
	 * @return static
89
	 */
90
	public function filterOne(array $condition)
91
	{
92
		$this->data_source->where($condition)->limit(1);
93
94
		return $this;
95
	}
96
97
98
	/**
99
	 * Filter by date
100
	 * @param  Filter\FilterDate $filter
101
	 * @return void
102
	 */
103 View Code Duplication
	public function applyFilterDate(Filter\FilterDate $filter)
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...
104
	{
105
		$conditions = $filter->getCondition();
106
107
		$date = DateTimeHelper::tryConvertToDateTime($conditions[$filter->getColumn()], [$filter->getPhpFormat()]);
108
109
		$this->data_source->where("DATE({$filter->getColumn()}) = ?", $date->format('Y-m-d'));
110
	}
111
112
113
	/**
114
	 * Filter by date range
115
	 * @param  Filter\FilterDateRange $filter
116
	 * @return void
117
	 */
118 View Code Duplication
	public function applyFilterDateRange(Filter\FilterDateRange $filter)
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...
119
	{
120
		$conditions = $filter->getCondition();
121
122
		$value_from = $conditions[$filter->getColumn()]['from'];
123
		$value_to   = $conditions[$filter->getColumn()]['to'];
124
125
		if ($value_from) {
126
			$date_from = DateTimeHelper::tryConvertToDateTime($value_from, [$filter->getPhpFormat()]);
127
			$date_from->setTime(0, 0, 0);
128
129
			$this->data_source->where("DATE({$filter->getColumn()}) >= ?", $date_from->format('Y-m-d'));
130
		}
131
132
		if ($value_to) {
133
			$date_to = DateTimeHelper::tryConvertToDateTime($value_to, [$filter->getPhpFormat()]);
134
			$date_to->setTime(23, 59, 59);
135
136
			$this->data_source->where("DATE({$filter->getColumn()}) <= ?", $date_to->format('Y-m-d'));
137
		}
138
	}
139
140
141
	/**
142
	 * Filter by range
143
	 * @param  Filter\FilterRange $filter
144
	 * @return void
145
	 */
146 View Code Duplication
	public function applyFilterRange(Filter\FilterRange $filter)
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...
147
	{
148
		$conditions = $filter->getCondition();
149
150
		$value_from = $conditions[$filter->getColumn()]['from'];
151
		$value_to   = $conditions[$filter->getColumn()]['to'];
152
153
		if ($value_from) {
154
			$this->data_source->where("{$filter->getColumn()} >= ?", $value_from);
155
		}
156
157
		if ($value_to) {
158
			$this->data_source->where("{$filter->getColumn()} <= ?", $value_to);
159
		}
160
	}
161
162
163
	/**
164
	 * Filter by keyword
165
	 * @param  Filter\FilterText $filter
166
	 * @return void
167
	 */
168
	public function applyFilterText(Filter\FilterText $filter)
169
	{
170
		$or = [];
171
		$args = [];
172
		$big_or = '(';
173
		$big_or_args = [];
174
		$condition = $filter->getCondition();
175
176
		foreach ($condition as $column => $value) {
177
178
			$like = '(';
179
			$args = [];
180
181
			if($filter->isExactSearch()){
182
				$like .=  "$column = ? OR ";
183
				$args[] = "$value";
184
			} else {
185 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...
186
					$words = [$value];
187
				} else {
188
					$words = explode(' ', $value);
189
				}
190
				foreach ($words as $word) {
191
					$like .= "$column LIKE ? OR ";
192
					$args[] = "%$word%";
193
				}
194
			}
195
			$like = substr($like, 0, strlen($like) - 4) . ')';
196
197
			$or[] = $like;
198
			$big_or .= "$like OR ";
199
			$big_or_args = array_merge($big_or_args, $args);
200
		}
201
202
		if (sizeof($or) > 1) {
203
			$big_or = substr($big_or, 0, strlen($big_or) - 4).')';
204
205
			$query = array_merge([$big_or], $big_or_args);
206
207
			call_user_func_array([$this->data_source, 'where'], $query);
208
		} else {
209
			$query = array_merge($or, $args);
210
211
			call_user_func_array([$this->data_source, 'where'], $query);
212
		}
213
	}
214
215
216
	/**
217
	 * Filter by multi select value
218
	 * @param  Filter\FilterMultiSelect $filter
219
	 * @return void
220
	 */
221
	public function applyFilterMultiSelect(Filter\FilterMultiSelect $filter)
222
	{
223
		$condition = $filter->getCondition();
224
		$values = $condition[$filter->getColumn()];
225
		$or = '(';
226
227
		if (sizeof($values) > 1) {
228
			$length = sizeof($values);
229
			$i = 1;
230
		
231
			foreach ($values as $value) {
232
				if ($i == $length) {
233
					$or .= $filter->getColumn() . ' = ?)';
234
				} else {
235
					$or .= $filter->getColumn() . ' = ? OR ';
236
				}
237
238
				$i++;
239
			}
240
241
			array_unshift($values, $or);
242
243
			call_user_func_array([$this->data_source, 'where'], $values);
244
		} else {
245
			$this->data_source->where($filter->getColumn() . ' = ?', reset($values));
246
		}
247
	}
248
249
250
	/**
251
	 * Filter by select value
252
	 * @param  Filter\FilterSelect $filter
253
	 * @return void
254
	 */
255
	public function applyFilterSelect(Filter\FilterSelect $filter)
256
	{
257
		$this->data_source->where($filter->getCondition());
258
	}
259
260
261
	/**
262
	 * Apply limit and offset on data
263
	 * @param int $offset
264
	 * @param int $limit
265
	 * @return static
266
	 */
267
	public function limit($offset, $limit)
268
	{
269
		$this->data = $this->data_source->limit($limit, $offset)->fetchAll();
270
271
		return $this;
272
	}
273
274
275
	/**
276
	 * Sort data
277
	 * @param  Sorting $sorting
278
	 * @return static
279
	 */
280 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...
281
	{
282
		if (is_callable($sorting->getSortCallback())) {
283
			call_user_func(
284
				$sorting->getSortCallback(),
285
				$this->data_source,
286
				$sorting->getSort()
287
			);
288
289
			return $this;
290
		}
291
292
		$sort = $sorting->getSort();
293
294
		if (!empty($sort)) {
295
			$this->data_source->getSqlBuilder()->setOrder([], []);
296
297
			foreach ($sort as $column => $order) {
298
				$this->data_source->order("$column $order");
299
			}
300
		} else {
301
			/**
302
			 * Has the statement already a order by clause?
303
			 */
304
			if (!$this->data_source->getSqlBuilder()->getOrder()) {
305
				$this->data_source->order($this->primary_key);
306
			}
307
		}
308
309
		return $this;
310
	}
311
312
	/**
313
	 * @param string $aggregation_type
314
	 * @param string $column
315
	 * @return mixed|void
316
	 */
317
	public function addAggregationColumn($aggregation_type, $column)
318
	{
319
		$this->aggregations[$column] = $aggregation_type;
320
	}
321
322
	/**
323
	 * get aggregation row
324
	 * @return array
325
	 */
326
	public function getAggregationData()
327
	{
328
		$result = [];
329
		//there should really be some better way to do this and get all results in one query, this could be big performance issue on bigger tables
330
		foreach ($this->aggregations as $column => $aggregation_type) {
331
			$result[$column] = $this->data_source->aggregation($aggregation_type . '(' . $column . ')');
332
		}
333
		return $result;
334
	}
335
}
336