Completed
Push — master ( e98ec0...b5ecb4 )
by Arjay
07:49
created

CollectionDataTable::canCreate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Yajra\DataTables;
4
5
use Illuminate\Contracts\Support\Arrayable;
6
use Illuminate\Support\Arr;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Str;
9
10
class CollectionDataTable extends DataTableAbstract
11
{
12
    /**
13
     * Collection object
14
     *
15
     * @var \Illuminate\Support\Collection
16
     */
17
    public $collection;
18
19
    /**
20
     * Collection object
21
     *
22
     * @var \Illuminate\Support\Collection
23
     */
24
    public $original;
25
26
    /**
27
     * Can the DataTable engine be created with these parameters.
28
     *
29
     * @param mixed $source
30
     * @return boolean
31
     */
32
    public static function canCreate($source)
33
    {
34
        return is_array($source) || $source instanceof Collection;
35
    }
36
37
    /**
38
     * Factory method, create and return an instance for the DataTable engine.
39
     *
40
     * @param array|\Illuminate\Support\Collection $source
41
     * @return CollectionDataTable|DataTableAbstract
42
     */
43
    public static function create($source)
44
    {
45
        if (is_array($source)) {
46
            $source = new Collection($source);
47
        }
48
49
        return parent::create($source);
50
    }
51
52
    /**
53
     * CollectionEngine constructor.
54
     *
55
     * @param \Illuminate\Support\Collection $collection
56
     */
57
    public function __construct(Collection $collection)
58
    {
59
        $this->request    = app('datatables.request');
60
        $this->config     = app('datatables.config');
61
        $this->collection = $collection;
62
        $this->original   = $collection;
63
        $this->columns    = array_keys($this->serialize($collection->first()));
64
    }
65
66
    /**
67
     * Serialize collection.
68
     *
69
     * @param  mixed $collection
70
     * @return mixed|null
71
     */
72
    protected function serialize($collection)
73
    {
74
        return $collection instanceof Arrayable ? $collection->toArray() : (array) $collection;
75
    }
76
77
    /**
78
     * Count results.
79
     *
80
     * @return integer
81
     */
82
    public function count()
83
    {
84
        return $this->collection->count() > $this->totalRecords ? $this->totalRecords : $this->collection->count();
85
    }
86
87
    /**
88
     * Perform column search.
89
     *
90
     * @return void
91
     */
92
    public function columnSearch()
93
    {
94
        $columns = $this->request->get('columns', []);
95
        for ($i = 0, $c = count($columns); $i < $c; $i++) {
96
            if ($this->request->isColumnSearchable($i)) {
97
                $this->isFilterApplied = true;
98
99
                $regex   = $this->request->isRegex($i);
100
                $column  = $this->getColumnName($i);
101
                $keyword = $this->request->columnKeyword($i);
102
103
                $this->collection = $this->collection->filter(
104
                    function ($row) use ($column, $keyword, $regex) {
105
                        $data = $this->serialize($row);
106
107
                        $value = Arr::get($data, $column);
108
109
                        if ($this->config->isCaseInsensitive()) {
110 View Code Duplication
                            if ($regex) {
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...
111
                                return preg_match('/' . $keyword . '/i', $value) == 1;
112
                            } else {
113
                                return strpos(Str::lower($value), Str::lower($keyword)) !== false;
114
                            }
115 View Code Duplication
                        } else {
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...
116
                            if ($regex) {
117
                                return preg_match('/' . $keyword . '/', $value) == 1;
118
                            } else {
119
                                return strpos($value, $keyword) !== false;
120
                            }
121
                        }
122
                    }
123
                );
124
            }
125
        }
126
    }
127
128
    /**
129
     * Perform pagination.
130
     *
131
     * @return void
132
     */
133
    public function paging()
134
    {
135
        $this->collection = $this->collection->slice(
136
            $this->request->input('start'),
137
            (int) $this->request->input('length') > 0 ? $this->request->input('length') : 10
138
        );
139
    }
140
141
    /**
142
     * Organizes works.
143
     *
144
     * @param bool $mDataSupport
145
     * @return \Illuminate\Http\JsonResponse
146
     */
147
    public function make($mDataSupport = true)
148
    {
149
        try {
150
            $this->totalRecords = $this->totalCount();
151
152
            if ($this->totalRecords) {
153
                $results   = $this->results();
154
                $processed = $this->processResults($results, $mDataSupport);
155
                $output    = $this->transform($results, $processed);
156
157
                $this->collection = collect($output);
158
                $this->ordering();
159
                $this->filterRecords();
160
                $this->paginate();
161
162
                $this->revertIndexColumn($mDataSupport);
163
            }
164
165
            return $this->render($this->collection->values()->all());
166
        } catch (\Exception $exception) {
167
            return $this->errorResponse($exception);
168
        }
169
    }
170
171
    /**
172
     * Count total items.
173
     *
174
     * @return integer
175
     */
176
    public function totalCount()
177
    {
178
        return $this->totalRecords ? $this->totalRecords : $this->collection->count();
179
    }
180
181
    /**
182
     * Get results.
183
     *
184
     * @return mixed
185
     */
186
    public function results()
187
    {
188
        return $this->collection->all();
189
    }
190
191
    /**
192
     * Revert transformed DT_Row_Index back to it's original values.
193
     *
194
     * @param bool $mDataSupport
195
     */
196
    private function revertIndexColumn($mDataSupport)
197
    {
198
        if ($this->columnDef['index']) {
199
            $index = $mDataSupport ? config('datatables.index_column', 'DT_Row_Index') : 0;
200
            $start = (int) $this->request->input('start');
201
            $this->collection->transform(function ($data) use ($index, &$start) {
202
                $data[$index] = ++$start;
203
204
                return $data;
205
            });
206
        }
207
    }
208
209
    /**
210
     * Perform global search for the given keyword.
211
     *
212
     * @param string $keyword
213
     */
214
    protected function globalSearch($keyword)
215
    {
216
        $columns = $this->request->columns();
217
        $keyword = $this->config->isCaseInsensitive() ? Str::lower($keyword) : $keyword;
218
219
        $this->collection = $this->collection->filter(function ($row) use ($columns, $keyword) {
220
            $this->isFilterApplied = true;
221
222
            $data = $this->serialize($row);
223
            foreach ($this->request->searchableColumnIndex() as $index) {
224
                $column = $this->getColumnName($index);
225
                $value  = Arr::get($data, $column);
226
                if (!$value || is_array($value)) {
227
                    if (!is_numeric($value)) {
228
                        continue;
229
                    } 
230
                    else {
231
                        $value = (string) $value;
232
                    }
233
                }
234
235
                $value = $this->config->isCaseInsensitive() ? Str::lower($value) : $value;
236
                if (Str::contains($value, $keyword)) {
237
                    return true;
238
                }
239
            }
240
241
            return false;
242
        });
243
    }
244
245
    /**
246
     * Perform default query orderBy clause.
247
     */
248
    protected function defaultOrdering()
249
    {
250
        $criteria = $this->request->orderableColumns();
251
        if (!empty($criteria)) {
252
            $sorter = $this->getSorter($criteria);
253
254
            $this->collection = $this->collection
255
                ->map(function ($data) {
256
                    return array_dot($data);
257
                })
258
                ->sort($sorter)
259
                ->map(function ($data) {
260
                    foreach ($data as $key => $value) {
261
                        unset($data[$key]);
262
                        array_set($data, $key, $value);
263
                    }
264
265
                    return $data;
266
                });
267
        }
268
    }
269
270
    /**
271
     * Get array sorter closure.
272
     *
273
     * @param array $criteria
274
     * @return \Closure
275
     */
276
    protected function getSorter(array $criteria)
277
    {
278
        $sorter = function ($a, $b) use ($criteria) {
279
            foreach ($criteria as $orderable) {
280
                $column    = $this->getColumnName($orderable['column']);
281
                $direction = $orderable['direction'];
282
                if ($direction === 'desc') {
283
                    $first  = $b;
284
                    $second = $a;
285
                } else {
286
                    $first  = $a;
287
                    $second = $b;
288
                }
289
                if ($this->config->isCaseInsensitive()) {
290
                    $cmp = strnatcasecmp($first[$column], $second[$column]);
291
                } else {
292
                    $cmp = strnatcmp($first[$column], $second[$column]);
293
                }
294
                if ($cmp != 0) {
295
                    return $cmp;
296
                }
297
            }
298
299
            // all elements were equal
300
            return 0;
301
        };
302
303
        return $sorter;
304
    }
305
306
    /**
307
     * Resolve callback parameter instance.
308
     *
309
     * @return $this
310
     */
311
    protected function resolveCallbackParameter()
312
    {
313
        return $this;
314
    }
315
}
316