Completed
Pull Request — master (#328)
by
unknown
38:08 queued 08:54
created

NextrasDataSource::getCount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
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 Ublaboo\DataGrid\Filter;
12
use Nextras\Orm\Mapper\Dbal\DbalCollection;
13
use Nette\Utils\Strings;
14
use Ublaboo\DataGrid\Utils\Sorting;
15
use Nextras\Orm\Collection\ICollection;
16
use Ublaboo\DataGrid\Utils\ArraysHelper;
17
18
class NextrasDataSource extends FilterableDataSource implements IDataSource
19
{
20
21
	/**
22
	 * @var DbalCollection
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
	/**
38
	 * @param ICollection  $data_source
39
	 * @param string       $primary_key
40
	 */
41
	public function __construct(ICollection $data_source, $primary_key)
42
	{
43
		$this->data_source = $data_source;
0 ignored issues
show
Documentation Bug introduced by
$data_source is of type object<Nextras\Orm\Collection\ICollection>, but the property $data_source was declared to be of type object<Nextras\Orm\Mapper\Dbal\DbalCollection>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
44
		$this->primary_key = $primary_key;
45
	}
46
47
48
	/********************************************************************************
49
	 *                          IDataSource implementation                          *
50
	 ********************************************************************************/
51
52
53
	/**
54
	 * Get count of data
55
	 * @return int
56
	 */
57
	public function getCount()
58
	{
59
		return $this->data_source->countStored();
60
	}
61
62
	/**
63
	 * Get the data
64
	 * @return array
65
	 */
66
	public function getData()
67
	{
68
		/**
69
		 * Paginator is better if the query uses ManyToMany associations
70
		 */
71
		return $this->data ?: $this->data_source->fetchAll();
72
	}
73
74
75
	/**
76
	 * Filter data - get one row
77
	 * @param array $condition
78
	 * @return static
79
	 */
80
	public function filterOne(array $condition)
81
	{
82
		$cond = [];
83
		foreach ($condition as $key => $value) {
84
			$cond[$this->prepareColumn($key)] = $value;
85
		}
86
		$this->data_source = $this->data_source->findBy($cond);
87
                
88
		return $this;
89
	}
90
91
92
	/**
93
	 * Filter by date
94
	 * @param  Filter\FilterDate $filter
95
	 * @return static
96
	 */
97
	public function applyFilterDate(Filter\FilterDate $filter)
98
	{
99
		foreach ($filter->getCondition() as $column => $value) {
100
			$date = \DateTime::createFromFormat($filter->getPhpFormat(), $value);
101
			$date_end = clone $date;
102
103
			$this->data_source = $this->data_source->findBy([
104
				$this->prepareColumn($column) . '>=' => $date->setTime(0, 0, 0),
105
				$this->prepareColumn($column) . '<=' => $date_end->setTime(23, 59, 59)
106
			]);
107
		}
108
109
		return $this;
110
	}
111
112
113
	/**
114
	 * Filter by date range
115
	 * @param  Filter\FilterDateRange $filter
116
	 * @return void
117
	 */
118
	public function applyFilterDateRange(Filter\FilterDateRange $filter)
119
	{
120
		$conditions = $filter->getCondition();
121
122
		$value_from = $conditions[$filter->getColumn()]['from'];
123
		$value_to = $conditions[$filter->getColumn()]['to'];
124
125
		$dataCondition = [];
126
		if ($value_from) {
127
			$date_from = \DateTime::createFromFormat($filter->getPhpFormat(), $value_from);
128
			$dataCondition[$this->prepareColumn($filter->getColumn()) . '>='] = $date_from->setTime(0, 0, 0);
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...Source::prepareColumn() 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...
129
		}
130
131
		if ($value_to) {
132
			$date_to = \DateTime::createFromFormat($filter->getPhpFormat(), $value_to);
133
			$dataCondition[$this->prepareColumn($filter->getColumn()) . '<='] = $date_to->setTime(23, 59, 59);
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...Source::prepareColumn() 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...
134
		}
135
136
		if (!empty($dataCondition)) {
137
			$this->data_source = $this->data_source->findBy($dataCondition);
138
		}
139
	}
140
141
142
	/**
143
	 * Filter by range
144
	 * @param  Filter\FilterRange $filter
145
	 * @return void
146
	 */
147
	public function applyFilterRange(Filter\FilterRange $filter)
148
	{
149
		$conditions = $filter->getCondition();
150
151
		$value_from = $conditions[$filter->getColumn()]['from'];
152
		$value_to = $conditions[$filter->getColumn()]['to'];
153
154
		$dataCondition = [];
155
156
		if ($value_from) {
157
			$dataCondition[$this->prepareColumn($filter->getColumn()) . '>='] = $value_from;
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...Source::prepareColumn() 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...
158
		}
159
160
		if ($value_to) {
161
			$dataCondition[$this->prepareColumn($filter->getColumn()) . '<='] = $value_to;
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...Source::prepareColumn() 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...
162
		}
163
164
		if (!empty($dataCondition)) {
165
			$this->data_source = $this->data_source->findBy($dataCondition);
166
		}
167
	}
168
169
170
	/**
171
	 * Filter by keyword
172
	 * @param  Filter\FilterText $filter
173
	 * @return void
174
	 */
175
	public function applyFilterText(Filter\FilterText $filter)
176
	{
177
		$condition = $filter->getCondition();
178
		$expr = '(';
179
		$params = [];
180
181
		foreach ($condition as $column => $value) {
182 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...
183
				$words = [$value];
184
			} else {
185
				$words = explode(' ', $value);
186
			}
187
188
			foreach ($words as $word) {
189
				$expr .= "%column LIKE %s OR ";
190
				$params[] = $column;
191
				$params[] = "%$word%";
192
			}
193
		}
194
195
		$expr = preg_replace('/ OR $/', ')', $expr);
196
197
		array_unshift($params, $expr);
198
199
		call_user_func_array([$this->data_source->getQueryBuilder(), 'andWhere'], $params);
200
	}
201
202
203
	/**
204
	 * Filter by multi select value
205
	 * @param  Filter\FilterMultiSelect $filter
206
	 * @return void
207
	 */
208
	public function applyFilterMultiSelect(Filter\FilterMultiSelect $filter)
209
	{
210
		$condition = $filter->getCondition();
211
		$values = $condition[$filter->getColumn()];
212
		$expr = '(';
213
214
		foreach ($values as $value) {
215
			$expr .= "%column = %any OR ";
216
			$params[] = $filter->getColumn();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
217
			$params[] = "$value";
218
		}
219
220
		$expr = preg_replace('/ OR $/', ')', $expr);
221
222
		array_unshift($params, $expr);
223
224
		call_user_func_array([$this->data_source->getQueryBuilder(), 'andWhere'], $params);
225
	}
226
227
228
	/**
229
	 * Filter by select value
230
	 * @param  Filter\FilterSelect $filter
231
	 * @return void
232
	 */
233
	public function applyFilterSelect(Filter\FilterSelect $filter)
234
	{
235
		$this->data_source = $this->data_source->findBy([$this->prepareColumn($filter->getColumn()) => $filter->getValue()]);
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...Source::prepareColumn() 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...
236
	}
237
238
239
	/**
240
	 * Apply limit and offset on data
241
	 * @param int $offset
242
	 * @param int $limit
243
	 * @return static
244
	 */
245
	public function limit($offset, $limit)
246
	{
247
		$this->data_source = $this->data_source->limitBy($limit, $offset);
248
249
		return $this;
250
	}
251
252
253
	/**
254
	 * Sort data
255
	 * @param  Sorting $sorting
256
	 * @return static
257
	 */
258
	public function sort(Sorting $sorting)
259
	{
260
		if (is_callable($sorting->getSortCallback())) {
261
			call_user_func(
262
				$sorting->getSortCallback(),
263
				$this->data_source,
264
				$sorting->getSort()
265
			);
266
267
			return $this;
268
		}
269
270
		$sort = $sorting->getSort();
271
272
		if (!empty($sort)) {
273
			foreach ($sort as $column => $order) {
274
				$this->data_source = $this->data_source->orderBy($column, $order);
275
			}
276
		} else {
277
			/**
278
			 * Has the statement already a order by clause?
279
			 */
280
			$order = $this->data_source->getQueryBuilder()->getClause('order');
281
282
			if (ArraysHelper::testEmpty($order)) {
283
				$this->data_source = $this->data_source->orderBy($this->primary_key);
284
			}
285
		}
286
287
		return $this;
288
	}
289
        
290
        /**
291
         * Adjust column from DataGrid 'foreignKey.column' to Nextras 'this->foreignKey->column'
292
         * @param string $column
293
         * @return string
294
         */
295
        private function prepareColumn($column) {
296
		if (Strings::contains($column, '.')) {
297
			return 'this->' . str_replace('.', '->', $column);
298
		}
299
		return $column;
300
	}
301
302
}
303