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