Test Failed
Push — master ( e70fcb...358eb6 )
by Terzi
03:12
created

Mutable::except()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3.0123

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 0
loc 15
ccs 8
cts 9
cp 0.8889
crap 3.0123
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace Terranet\Administrator\Collection;
4
5
use Closure;
6
use Illuminate\Support\Collection as BaseCollection;
7
use Terranet\Administrator\Contracts\Module\Sortable;
8
use Terranet\Administrator\Exception;
9
use Terranet\Administrator\Field\Text;
10
11
class Mutable extends BaseCollection
12
{
13
    /**
14
     * Push an item onto the end of the collection.
15
     *
16
     * @param  mixed $element
17
     * @param null|Closure $callback
18
     *
19
     * @return $this
20
     */
21 29
    public function push($element, Closure $callback = null): self
22
    {
23 29
        $element = $this->createElement($element);
24
25 29
        if ($callback) {
26 2
            $callback($element);
27
        }
28
29 29
        parent::push($element);
30
31 29
        return $this;
32
    }
33
34
    /**
35
     * Insert an element into collection at specified position.
36
     *
37
     * @param $element
38
     * @param $position
39
     * @param null|Closure $callback
40
     *
41
     * @throws Exception
42
     *
43
     * @return $this
44
     */
45 8
    public function insert($element, $position, Closure $callback = null): self
46
    {
47 8
        $element = $this->createElement($element);
48
49 8
        if ($callback) {
50 1
            $callback($element);
51
        }
52
53 8
        if (\is_string($position)) {
54 3
            $this->push($element);
55
56 3
            return $this->move($element->id(), $position);
57
        }
58
59 8
        if ($position >= $this->count()) {
60 4
            return $this->push($element);
61
        }
62
63 5
        if (0 === $position) {
64 3
            return $this->prepend($element);
65
        }
66
67 3
        $items = [];
68 3
        foreach ($this->all() as $index => $value) {
69 3
            if ($index === $position) {
70 3
                array_push($items, $element);
71
            }
72
73 3
            array_push($items, $value);
74
        }
75 3
        $this->items = $items;
76
77 3
        return $this;
78
    }
79
80
    /**
81
     * Get all items except for those with the specified keys.
82
     *
83
     * @param  array|mixed|string $keys
84
     *
85
     * @return static
86
     */
87 11
    public function except($keys)
88
    {
89 11
        if ($keys instanceof self) {
90
            $keys = $keys->all();
91 11
        } elseif (!\is_array($keys)) {
92 10
            $keys = \func_get_args();
93
        }
94
95
        $items = $this->filter(function ($element) use ($keys) {
96 11
            return !\in_array($element->id(), $keys, true);
97 11
        })->all();
98
99 11
        $this->items = array_values($items);
100
101 11
        return $this;
102
    }
103
104
    /**
105
     * Retrieve only visible items.
106
     *
107
     * @param string $page
108
     *
109
     * @return Mutable
110
     */
111
    public function visibleOnPage(string $page)
112
    {
113
        return $this->filter(function ($item) use ($page) {
114
            // @var Generic|Translatable $item
115
            return (($item instanceof Group) || $item->isVisibleOnPage($page)) && $item->visibleWhen();
116
        });
117
    }
118
119
    /**
120
     * Update elements behaviour.
121
     *
122
     * @param string $id
123
     * @param Closure $callback
124
     *
125
     * @throws Exception
126
     *
127
     * @return $this
128
     */
129 4
    public function update(string $id, Closure $callback): self
130
    {
131 4
        if (str_contains($id, ',')) {
0 ignored issues
show
Deprecated Code introduced by
The function str_contains() has been deprecated: Str::contains() should be used directly instead. Will be removed in Laravel 5.9. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

131
        if (/** @scrutinizer ignore-deprecated */ str_contains($id, ',')) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
132 1
            collect(explode(',', $id))
133 1
                ->map('trim')
134
                ->each(function ($element) use ($callback) {
135 1
                    $this->update($element, $callback);
136 1
                });
137
138 1
            return $this;
139
        }
140
141 4
        $element = $this->find($id);
142
143 4
        if ($element && $callback) {
144 4
            $newElement = $callback($element);
145 4
            if ($newElement !== $element) {
146
                $position = $this->position($id);
147
                $this->except($id);
148
                $this->insert($newElement, $position);
149
            }
150
        }
151
152 4
        return $this;
153
    }
154
155
    /**
156
     * Update many elements at once.
157
     *
158
     * @param array $ids
159
     *
160
     * @throws Exception
161
     *
162
     * @return $this
163
     */
164 2
    public function updateMany(array $ids = []): self
165
    {
166 2
        foreach ($ids as $id => $callback) {
167 2
            $this->update($id, $callback);
168
        }
169
170 2
        return $this;
171
    }
172
173
    /**
174
     * Move element.
175
     *
176
     * @param $id
177
     * @param int|mixed|string $position
178
     *
179
     * @throws Exception
180
     *
181
     * @return static
182
     *
183
     * @example: move('user_id', 4);
184
     * @example: move('user_id', 'before:name");
185
     * @example: move('user_id', 'after:id");
186
     */
187 8
    public function move(string $id, $position): self
188
    {
189 8
        if (is_numeric($position)) {
190 1
            return $this->toPosition($id, $position);
191
        }
192
193 7
        if (starts_with($position, 'before:')) {
0 ignored issues
show
Deprecated Code introduced by
The function starts_with() has been deprecated: Str::startsWith() should be used directly instead. Will be removed in Laravel 5.9. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

193
        if (/** @scrutinizer ignore-deprecated */ starts_with($position, 'before:')) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
194 3
            return $this->moveBefore($id, substr($position, 7));
195
        }
196
197 4
        if (starts_with($position, 'after:')) {
0 ignored issues
show
Deprecated Code introduced by
The function starts_with() has been deprecated: Str::startsWith() should be used directly instead. Will be removed in Laravel 5.9. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

197
        if (/** @scrutinizer ignore-deprecated */ starts_with($position, 'after:')) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
198 3
            return $this->moveAfter($id, substr($position, 6));
199
        }
200
201 1
        throw new Exception("Unknown moving direction: {$position}");
202
    }
203
204
    /**
205
     * Move element before another one.
206
     *
207
     * @param string $id
208
     * @param $target
209
     *
210
     * @throws Exception
211
     *
212
     * @return $this
213
     */
214 3
    public function moveBefore(string $id, $target)
215
    {
216 3
        if ($element = $this->find($id)) {
217 3
            $this->except($id);
218 3
            $targetPosition = $this->position($target);
219
220 3
            if ($targetPosition >= 0) {
221 3
                $this->insert($element, $targetPosition)->all();
222
            }
223
        }
224
225 3
        return $this;
226
    }
227
228
    /**
229
     * Move element after another one.
230
     *
231
     * @param string $id
232
     * @param $target
233
     *
234
     * @throws Exception
235
     *
236
     * @return $this
237
     */
238 3
    public function moveAfter(string $id, $target): self
239
    {
240 3
        if ($element = $this->find($id)) {
241 3
            $this->except($id);
242
243 3
            $targetPosition = $this->position($target);
244
245 3
            if ($targetPosition >= 0) {
246 3
                $this->insert($element, $targetPosition + 1)->all();
247
            }
248
        }
249
250 3
        return $this;
251
    }
252
253
    /**
254
     * Add a new elements group.
255
     *
256
     * @param string $id
257
     * @param Closure $callback
258
     *
259
     * @return $this
260
     */
261 1
    public function group(string $id, Closure $callback): self
262
    {
263 1
        $group = new Group($id);
264
265 1
        $callback($group);
266
267 1
        $this->push($group);
268
269 1
        return $this;
270
    }
271
272
    /**
273
     * Join existing elements to a group.
274
     *
275
     * @param array $elements
276
     * @param string $groupId
277
     * @param null|int|string $position
278
     *
279
     * @throws Exception
280
     *
281
     * @return $this
282
     */
283 2
    public function stack(array $elements, string $groupId, $position = null): self
284
    {
285 2
        $group = new Group($groupId);
286
287
        $this->filter(function ($element) use ($elements) {
288 2
            return \in_array($element->id(), $elements, true);
289
        })->each(function ($element) use ($group) {
290 2
            $group->push($element);
291 2
            $this->items = $this->except($element->id())->all();
292 2
        });
293
294 2
        if ($position) {
295 1
            $this->insert($group, $position);
296
        } else {
297 1
            $this->push($group);
298
        }
299
300 2
        return $this;
301
    }
302
303
    /**
304
     * Build a collection.
305
     *
306
     * @param $decorator
307
     *
308
     * @return static
309
     */
310
    public function build($decorator)
311
    {
312
        return $this->map(function ($element) use ($decorator) {
313
            if ($element instanceof Group) {
314
                $element->map(function ($e) use ($decorator) {
315
                    return $decorator->make($e);
316
                });
317
318
                return $element;
319
            }
320
321
            return $decorator->make($element);
322
        });
323
    }
324
325
    /**
326
     * Find an element.
327
     *
328
     * @param string $id
329
     *
330
     * @throws Exception
331
     *
332
     * @return mixed
333
     */
334 16
    public function find(string $id)
335
    {
336
        return $this->first(function ($element) use ($id) {
337 16
            return $element && $element->id() === $id;
338 16
        });
339
    }
340 16
341 1
    /**
342
     * Find an element position.
343
     *
344 16
     * @param string $id
345
     *
346
     * @throws Exception
347
     *
348
     * @return null|int|string
349
     */
350
    public function position(string $id): int
351
    {
352
        $i = 0;
353
        foreach ($this->all() as $item) {
354
            if ($item->id() === $id) {
355
                return $i;
356 7
            }
357
358 7
            ++$i;
359 7
        }
360 7
361 7
        return $this->notFound($id);
362
    }
363
364 3
    /**
365
     * Make elements sortable.
366
     *
367 1
     * @param mixed string|array $keys
368
     * @param \Closure $callback
369
     * @example: sortable(['title'])
370
     * @example: sortable(['title' => function($query) {  }])
371
     *
372
     * @return Mutable
373
     */
374
    public function sortable($keys, \Closure $callback = null)
375
    {
376
        if (\is_array($keys)) {
377
            foreach ($keys as $id => $callback) {
378
                if (\is_string($id)) {
379
                    $this->sortable($id, $callback);
380
                } else {
381
                    $this->sortable($callback);
382
                }
383
            }
384
385
            return $this;
386
        }
387
388
        $module = app('scaffold.module');
0 ignored issues
show
Bug introduced by
The function app was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

388
        $module = /** @scrutinizer ignore-call */ app('scaffold.module');
Loading history...
389
        if ($module instanceof Sortable && method_exists($module, 'addSortable')) {
390
            $module->addSortable($keys, $callback);
391
        }
392
393
        return $this;
394
    }
395
396
    /**
397
     * Remove column from Sortable collection.
398
     *
399
     * @param array|string $keys
400
     *
401
     * @return self
402
     */
403
    public function disableSorting($keys): self
404
    {
405
        if (!\is_array($keys)) {
406
            $keys = \func_get_args();
407
        }
408
409
        $module = app('scaffold.module');
0 ignored issues
show
Bug introduced by
The function app was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

409
        $module = /** @scrutinizer ignore-call */ app('scaffold.module');
Loading history...
410
        if ($module instanceof Sortable && method_exists($module, 'removeSortable')) {
411
            foreach ($keys as $key) {
412
                $module->removeSortable($key);
413
            }
414
        }
415
416
        return $this;
417
    }
418
419
    /**
420
     * Move an element to a position.
421
     *
422
     * @param string $id
423
     * @param int|string $position
424
     *
425
     * @throws Exception
426
     *
427
     * @return static
428
     */
429
    protected function toPosition(string $id, $position): self
430
    {
431
        $element = $this->find($id);
432
433
        return $this
434
            ->except($id)
435 1
            ->insert($element, $position);
436
    }
437 1
438
    /**
439
     * @param string $id
440 1
     *
441 1
     * @throws Exception
442
     */
443
    protected function notFound(string $id)
444
    {
445
        throw new Exception(sprintf('Element [%s] does not exist.', $id));
446
    }
447
448
    /**
449 2
     * Create element object from string.
450
     *
451 2
     * @param $element
452
     *
453
     * @return mixed
454
     */
455
    protected function createElement($element)
456
    {
457
        if (\is_string($element)) {
458
            $element = Text::make($element, $element);
459
        }
460
461 29
        return $element;
462
    }
463
}
464