Test Failed
Push — master ( 0c2ad6...e8c327 )
by Terzi
05:02
created

Mutable::notFound()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
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
     * @return $this
19
     */
20
    public function push($element, Closure $callback = null): self
21 29
    {
22
        $element = $this->createElement($element);
23 29
24
        if ($callback) {
25 29
            $callback($element);
26 2
        }
27
28
        parent::push($element);
29 29
30
        return $this;
31 29
    }
32
33
    /**
34
     * Insert an element into collection at specified position.
35
     *
36
     * @param $element
37
     * @param $position
38
     * @param  null|Closure  $callback
39
     * @return $this
40
     * @throws Exception
41
     */
42
    public function insert($element, $position, Closure $callback = null): self
43
    {
44
        $element = $this->createElement($element);
45 8
46
        if ($callback) {
47 8
            $callback($element);
48
        }
49 8
50 1
        if (\is_string($position)) {
51
            $this->push($element);
52
53 8
            return $this->move($element->id(), $position);
54 3
        }
55
56 3
        if ($position >= $this->count()) {
57
            return $this->push($element);
58
        }
59 8
60 4
        if (0 === $position) {
61
            return $this->prepend($element);
62
        }
63 5
64 3
        $items = [];
65
        foreach ($this->all() as $index => $value) {
66
            if ($index === $position) {
67 3
                array_push($items, $element);
68 3
            }
69 3
70 3
            array_push($items, $value);
71
        }
72
        $this->items = $items;
73 3
74
        return $this;
75 3
    }
76
77 3
    /**
78
     * Get all items except for those with the specified keys.
79
     *
80
     * @param  array|mixed|string  $keys
81
     * @return static
82
     */
83
    public function except($keys)
84
    {
85
        if ($keys instanceof self) {
86
            $keys = $keys->all();
87 11
        } elseif (!\is_array($keys)) {
88
            $keys = \func_get_args();
89 11
        }
90
91 11
        $items = $this->filter(function ($element) use ($keys) {
92 10
            return !\in_array($element->id(), $keys, true);
93
        })->all();
94
95
        $this->items = array_values($items);
96 11
97 11
        return $this;
98
    }
99 11
100
    /**
101 11
     * Retrieve only visible items.
102
     *
103
     * @param  string  $page
104
     * @return Mutable
105
     */
106
    public function visibleOnPage(string $page)
107
    {
108
        return $this->filter(function ($item) use ($page) {
109
            // @var Generic|Translatable $item
110
            return (($item instanceof Group) || $item->isVisibleOnPage($page)) && $item->visibleWhen();
111
        });
112
    }
113
114
    /**
115
     * Update elements behaviour.
116
     *
117
     * @param  string  $id
118
     * @param  Closure  $callback
119
     * @return $this
120
     * @throws Exception
121
     */
122
    public function update(string $id, Closure $callback): self
123
    {
124
        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

124
        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...
125
            collect(explode(',', $id))
126
                ->map('trim')
127
                ->each(function ($element) use ($callback) {
128
                    $this->update($element, $callback);
129 4
                });
130
131 4
            return $this;
132 1
        }
133 1
134
        $element = $this->find($id);
135 1
136 1
        if ($element && $callback) {
137
            $newElement = $callback($element);
138 1
            if ($newElement !== $element) {
139
                $position = $this->position($id);
140
                $this->except($id);
141 4
                $this->insert($newElement, $position);
142
            }
143 4
        }
144 4
145 4
        return $this;
146
    }
147
148
    /**
149
     * Replace the field.
150
     *
151
     * @param  mixed  $id
152 4
     * @param $value
153
     * @return $this|BaseCollection
154
     * @throws Exception
155
     */
156
    public function switch($id, $value)
157
    {
158
        if ($position = $this->position($id)) {
159
            $this->offsetSet($position, $value);
160
        }
161
162
        return $this;
163
    }
164 2
165
    /**
166 2
     * Update many elements at once.
167 2
     *
168
     * @param  array  $ids
169
     * @return $this
170 2
     * @throws Exception
171
     */
172
    public function updateMany(array $ids = []): self
173
    {
174
        foreach ($ids as $id => $callback) {
175
            $this->update($id, $callback);
176
        }
177
178
        return $this;
179
    }
180
181
    /**
182
     * Move element.
183
     *
184
     * @param $id
185
     * @param  int|mixed|string  $position
186
     * @return static
187 8
     * @throws Exception
188
     * @example: move('user_id', 4);
189 8
     * @example: move('user_id', 'before:name");
190 1
     * @example: move('user_id', 'after:id");
191
     */
192
    public function move(string $id, $position): self
193 7
    {
194 3
        if (is_numeric($position)) {
195
            return $this->toPosition($id, $position);
196
        }
197 4
198 3
        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

198
        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...
199
            return $this->moveBefore($id, substr($position, 7));
200
        }
201 1
202
        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

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

380
        $module = /** @scrutinizer ignore-call */ app('scaffold.module');
Loading history...
381
        if ($module instanceof Sortable && method_exists($module, 'addSortable')) {
382
            $module->addSortable($keys, $callback);
383
        }
384
385
        return $this;
386
    }
387
388
    /**
389
     * Remove column from Sortable collection.
390
     *
391
     * @param  array|string  $keys
392
     * @return self
393
     */
394
    public function disableSorting($keys): self
395
    {
396
        if (!\is_array($keys)) {
397
            $keys = \func_get_args();
398
        }
399
400
        $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

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