Passed
Push — master ( 09e224...77eb7f )
by Quentin
08:10 queued 01:38
created

ModuleController::applyFiltersDefaultOptions()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 11.1035

Importance

Changes 0
Metric Value
cc 5
eloc 7
nc 4
nop 0
dl 0
loc 15
ccs 3
cts 8
cp 0.375
crap 11.1035
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
namespace A17\Twill\Http\Controllers\Admin;
4
5
use A17\Twill\Helpers\FlashLevel;
6
use Illuminate\Contracts\Foundation\Application;
7
use Illuminate\Http\Request;
8
use Illuminate\Support\Arr;
9
use Illuminate\Support\Collection;
10
use Illuminate\Support\Facades\App;
11
use Illuminate\Support\Facades\Auth;
12
use Illuminate\Support\Facades\Config;
13
use Illuminate\Support\Facades\Redirect;
14
use Illuminate\Support\Facades\Response;
15
use Illuminate\Support\Facades\Route;
16
use Illuminate\Support\Facades\Session;
17
use Illuminate\Support\Facades\URL;
18
use Illuminate\Support\Facades\View;
19
use Illuminate\Support\Str;
20
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
21
22
abstract class ModuleController extends Controller
23
{
24
    /**
25
     * @var Application
26
     */
27
    protected $app;
28
29
    /**
30
     * @var Request
31
     */
32
    protected $request;
33
34
    /**
35
     * @var string
36
     */
37
    protected $namespace;
38
39
    /**
40
     * @var string
41
     */
42
    protected $routePrefix;
43
44
    /**
45
     * @var string
46
     */
47
    protected $moduleName;
48
49
    /**
50
     * @var string
51
     */
52
    protected $modelName;
53
54
    /**
55
     * @var string
56
     */
57
    protected $modelTitle;
58
59
    /**
60
     * @var \A17\Twill\Repositories\ModuleRepository
61
     */
62
    protected $repository;
63
64
    /**
65
     * Options of the index view.
66
     *
67
     * @var array
68
     */
69
    protected $defaultIndexOptions = [
70
        'create' => true,
71
        'edit' => true,
72
        'publish' => true,
73
        'bulkPublish' => true,
74
        'feature' => false,
75
        'bulkFeature' => false,
76
        'restore' => true,
77
        'bulkRestore' => true,
78
        'forceDelete' => true,
79
        'bulkForceDelete' => true,
80
        'delete' => true,
81
        'bulkDelete' => true,
82
        'reorder' => false,
83
        'permalink' => true,
84
        'bulkEdit' => true,
85
        'editInModal' => false,
86
    ];
87
88
    /**
89
     * Relations to eager load for the index view
90
     *
91
     * @var array
92
     */
93
    protected $indexWith = [];
94
95
    /**
96
     * Relations to eager load for the form view.
97
     *
98
     * @var array
99
     */
100
    protected $formWith = [];
101
102
    /**
103
     * Relation count to eager load for the form view.
104
     *
105
     * @var array
106
     */
107
    protected $formWithCount = [];
108
109
    /**
110
     * Additional filters for the index view.
111
     *
112
     * To automatically have your filter added to the index view use the following convention:
113
     * suffix the key containing the list of items to show in the filter by 'List' and
114
     * name it the same as the filter you defined in this array.
115
     *
116
     * Example: 'fCategory' => 'category_id' here and 'fCategoryList' in indexData()
117
     * By default, this will run a where query on the category_id column with the value
118
     * of fCategory if found in current request parameters. You can intercept this behavior
119
     * from your repository in the filter() function.
120
     *
121
     * @var array
122
     */
123
    protected $filters = [];
124
125
    /**
126
     * Additional links to display in the listing filter
127
     *
128
     * @var array
129
     */
130
    protected $filterLinks = [];
131
132
    /**
133
     * Filters that are selected by default in the index view.
134
     *
135
     * Example: 'filter_key' => 'default_filter_value'
136
     *
137
     * @var array
138
     */
139
    protected $filtersDefaultOptions = [];
140
141
    /**
142
     * Default orders for the index view.
143
     *
144
     * @var array
145
     */
146
    protected $defaultOrders = [
147
        'created_at' => 'desc',
148
    ];
149
150
    /**
151
     * @var int
152
     */
153
    protected $perPage = 20;
154
155
    /**
156
     * Name of the index column to use as name column.
157
     *
158
     * @var string
159
     */
160
    protected $titleColumnKey = 'title';
161
162
    /**
163
     * Attribute to use as title in forms.
164
     *
165
     * @var string
166
     */
167
    protected $titleFormKey;
168
169
    /**
170
     * Feature field name if the controller is using the feature route (defaults to "featured").
171
     *
172
     * @var string
173
     */
174
    protected $featureField = 'featured';
175
176
    /**
177
     * Indicates if this module is edited through a parent module.
178
     *
179
     * @var bool
180
     */
181
    protected $submodule = false;
182
183
    /**
184
     * @var int|null
185
     */
186
    protected $submoduleParentId = null;
187
188
    /**
189
     * Can be used in child classes to disable the content editor (full screen block editor).
190
     *
191
     * @var bool
192
     */
193
    protected $disableEditor = false;
194
195
    /**
196
     * @var array
197
     */
198
    protected $indexOptions;
199
200
    /**
201
     * @var array
202
     */
203
    protected $indexColumns;
204
205
    /**
206
     * @var array
207
     */
208
    protected $browserColumns;
209
210
    /**
211
     * @var string
212
     */
213
    protected $permalinkBase;
214
215
    /**
216
     * @var array
217
     */
218
    protected $defaultFilters;
219
220
    /**
221
     * @var string
222
     */
223
    protected $viewPrefix;
224
225
    /**
226
     * @var string
227
     */
228
    protected $previewView;
229
230
    /**
231
     * List of permissions keyed by a request field. Can be used to prevent unauthorized field updates.
232
     *
233
     * @var array
234
     */
235
    protected $fieldsPermissions = [];
236
237 40
    public function __construct(Application $app, Request $request)
238
    {
239 40
        parent::__construct();
240 40
        $this->app = $app;
241 40
        $this->request = $request;
242
243 40
        $this->setMiddlewarePermission();
244
245 40
        $this->modelName = $this->getModelName();
246 40
        $this->routePrefix = $this->getRoutePrefix();
247 40
        $this->namespace = $this->getNamespace();
248 40
        $this->repository = $this->getRepository();
249 40
        $this->viewPrefix = $this->getViewPrefix();
250 40
        $this->modelTitle = $this->getModelTitle();
251
252
        /*
253
         * Default filters for the index view
254
         * By default, the search field will run a like query on the title field
255
         */
256 40
        if (!isset($this->defaultFilters)) {
257 26
            $this->defaultFilters = [
258 26
                'search' => ($this->moduleHas('translations') ? '' : '%') . $this->titleColumnKey,
259
            ];
260
        }
261
262
        /*
263
         * Apply any filters that are selected by default
264
         */
265 40
        $this->applyFiltersDefaultOptions();
266
267
        /*
268
         * Available columns of the index view
269
         */
270 40
        if (!isset($this->indexColumns)) {
271 13
            $this->indexColumns = [
272 13
                $this->titleColumnKey => [
273 13
                    'title' => ucfirst($this->titleColumnKey),
274 13
                    'field' => $this->titleColumnKey,
275
                    'sort' => true,
276
                ],
277
            ];
278
        }
279
280
        /*
281
         * Available columns of the browser view
282
         */
283 40
        if (!isset($this->browserColumns)) {
284 40
            $this->browserColumns = [
285 40
                $this->titleColumnKey => [
286 40
                    'title' => ucfirst($this->titleColumnKey),
287 40
                    'field' => $this->titleColumnKey,
288
                ],
289
            ];
290
        }
291 40
    }
292
293
    /**
294
     * @return void
295
     */
296 40
    protected function setMiddlewarePermission()
297
    {
298 40
        $this->middleware('can:list', ['only' => ['index', 'show']]);
299 40
        $this->middleware('can:edit', ['only' => ['store', 'edit', 'update']]);
300 40
        $this->middleware('can:publish', ['only' => ['publish', 'feature', 'bulkPublish', 'bulkFeature']]);
301 40
        $this->middleware('can:reorder', ['only' => ['reorder']]);
302 40
        $this->middleware('can:delete', ['only' => ['destroy', 'bulkDelete', 'restore', 'bulkRestore', 'forceDelete', 'bulkForceDelete', 'restoreRevision']]);
303 40
    }
304
305
    /**
306
     * @param int|null $parentModuleId
307
     * @return array|\Illuminate\View\View
308
     */
309 6
    public function index($parentModuleId = null)
310
    {
311 6
        $this->submodule = isset($parentModuleId);
312 6
        $this->submoduleParentId = $parentModuleId;
313
314 6
        $indexData = $this->getIndexData($this->submodule ? [
315
            $this->getParentModuleForeignKey() => $this->submoduleParentId,
316 6
        ] : []);
317
318 6
        if ($this->request->ajax()) {
319 3
            return $indexData + ['replaceUrl' => true];
320
        }
321
322 3
        if ($this->request->has('openCreate') && $this->request->get('openCreate')) {
323
            $indexData += ['openCreate' => true];
324
        }
325
326 3
        $view = Collection::make([
327 3
            "$this->viewPrefix.index",
328 3
            "twill::$this->moduleName.index",
329 3
            "twill::layouts.listing",
330
        ])->first(function ($view) {
331 3
            return View::exists($view);
332 3
        });
333
334 3
        return View::make($view, $indexData);
335
    }
336
337
    /**
338
     * @return \Illuminate\Http\JsonResponse
339
     */
340 2
    public function browser()
341
    {
342 2
        return Response::json($this->getBrowserData());
343
    }
344
345
    /**
346
     * @param int|null $parentModuleId
347
     * @return \Illuminate\Http\JsonResponse
348
     */
349 21
    public function store($parentModuleId = null)
350
    {
351 21
        $input = $this->validateFormRequest()->all();
352 21
        $optionalParent = $parentModuleId ? [$this->getParentModuleForeignKey() => $parentModuleId] : [];
353
354 21
        $item = $this->repository->create($input + $optionalParent);
355
356 21
        activity()->performedOn($item)->log('created');
357
358 21
        $this->fireEvent($input);
359
360 21
        Session::put($this->moduleName . '_retain', true);
361
362 21
        if ($this->getIndexOption('editInModal')) {
363 2
            return $this->respondWithSuccess('Content saved. All good!');
364
        }
365
366 19
        return $this->respondWithRedirect(moduleRoute(
367 19
            $this->moduleName,
368 19
            $this->routePrefix,
369 19
            'edit',
370 19
            array_filter([$parentModuleId]) + [Str::singular($this->moduleName) => $item->id]
371
        ));
372
    }
373
374
    /**
375
     * @param int|$id
376
     * @param int|null $submoduleId
377
     * @return \Illuminate\Http\RedirectResponse
378
     */
379 1
    public function show($id, $submoduleId = null)
380
    {
381 1
        if ($this->getIndexOption('editInModal')) {
382
            return Redirect::to(moduleRoute($this->moduleName, $this->routePrefix, 'index'));
383
        }
384
385 1
        return $this->redirectToForm($submoduleId ?? $id);
386
    }
387
388
    /**
389
     * @param int $id
390
     * @param int|null $submoduleId
391
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\View\View
392
     */
393 5
    public function edit($id, $submoduleId = null)
394
    {
395 5
        $this->submodule = isset($submoduleId);
396 5
        $this->submoduleParentId = $id;
397
398 5
        if ($this->getIndexOption('editInModal')) {
399 2
            return $this->request->ajax()
400 1
            ? Response::json($this->modalFormData($submoduleId ?? $id))
401 2
            : Redirect::to(moduleRoute($this->moduleName, $this->routePrefix, 'index'));
402
        }
403
404 3
        $this->setBackLink();
405
406 3
        $view = Collection::make([
407 3
            "$this->viewPrefix.form",
408 3
            "twill::$this->moduleName.form",
409 3
            "twill::layouts.form",
410
        ])->first(function ($view) {
411 3
            return View::exists($view);
412 3
        });
413
414 3
        return View::make($view, $this->form($submoduleId ?? $id));
415
    }
416
417
    /**
418
     * @param int $id
419
     * @param int|null $submoduleId
420
     * @return \Illuminate\Http\JsonResponse
421
     */
422 7
    public function update($id, $submoduleId = null)
423
    {
424 7
        $this->submodule = isset($submoduleId);
425 7
        $this->submoduleParentId = $id;
426
427 7
        $item = $this->repository->getById($submoduleId ?? $id);
428 7
        $input = $this->request->all();
429
430 7
        if (isset($input['cmsSaveType']) && $input['cmsSaveType'] === 'cancel') {
431
            return $this->respondWithRedirect(moduleRoute(
432
                $this->moduleName,
433
                $this->routePrefix,
434
                'edit',
435
                [Str::singular($this->moduleName) => $id]
436
            ));
437
        } else {
438 7
            $formRequest = $this->validateFormRequest();
439
440 7
            $this->repository->update($submoduleId ?? $id, $formRequest->all());
441
442 7
            activity()->performedOn($item)->log('updated');
443
444 7
            $this->fireEvent();
445
446 7
            if (isset($input['cmsSaveType'])) {
447 7
                if (Str::endsWith($input['cmsSaveType'], '-close')) {
448
                    return $this->respondWithRedirect($this->getBackLink());
449 7
                } elseif (Str::endsWith($input['cmsSaveType'], '-new')) {
450
                    return $this->respondWithRedirect(moduleRoute(
451
                        $this->moduleName,
452
                        $this->routePrefix,
453
                        'index',
454
                        ['openCreate' => true]
455
                    ));
456 7
                } elseif ($input['cmsSaveType'] === 'restore') {
457
                    Session::flash('status', "Revision restored.");
458
459
                    return $this->respondWithRedirect(moduleRoute(
460
                        $this->moduleName,
461
                        $this->routePrefix,
462
                        'edit',
463
                        [Str::singular($this->moduleName) => $id]
464
                    ));
465
                }
466
            }
467
468 7
            if ($this->moduleHas('revisions')) {
469 6
                return Response::json([
470 6
                    'message' => 'Content saved. All good!',
471
                    'variant' => FlashLevel::SUCCESS,
472 6
                    'revisions' => $item->revisionsArray(),
473
                ]);
474
            }
475
476 1
            return $this->respondWithSuccess('Content saved. All good!');
477
        }
478
    }
479
480
    /**
481
     * @param int $id
482
     * @return \Illuminate\View\View
483
     */
484 1
    public function preview($id)
485
    {
486 1
        if ($this->request->has('revisionId')) {
487
            $item = $this->repository->previewForRevision($id, $this->request->get('revisionId'));
0 ignored issues
show
Bug introduced by
The method previewForRevision() does not exist on A17\Twill\Repositories\ModuleRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

487
            /** @scrutinizer ignore-call */ 
488
            $item = $this->repository->previewForRevision($id, $this->request->get('revisionId'));
Loading history...
488
        } else {
489 1
            $formRequest = $this->validateFormRequest();
490 1
            $item = $this->repository->preview($id, $formRequest->all());
0 ignored issues
show
Bug introduced by
The method preview() does not exist on A17\Twill\Repositories\ModuleRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

490
            /** @scrutinizer ignore-call */ 
491
            $item = $this->repository->preview($id, $formRequest->all());
Loading history...
491
        }
492
493 1
        if ($this->request->has('activeLanguage')) {
494
            App::setLocale($this->request->get('activeLanguage'));
495
        }
496
497 1
        $previewView = $this->previewView ?? (Config::get('twill.frontend.views_path', 'site') . '.' . Str::singular($this->moduleName));
498
499 1
        return View::exists($previewView) ? View::make($previewView, array_replace([
500 1
            'item' => $item,
501 1
        ], $this->previewData($item))) : View::make('twill::errors.preview', [
0 ignored issues
show
Bug introduced by
It seems like $item can also be of type Illuminate\Database\Eloquent\Builder; however, parameter $item of A17\Twill\Http\Controlle...ntroller::previewData() does only seem to accept Illuminate\Http\Request, maybe add an additional type check? ( Ignorable by Annotation )

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

501
        ], $this->previewData(/** @scrutinizer ignore-type */ $item))) : View::make('twill::errors.preview', [
Loading history...
502 1
            'moduleName' => Str::singular($this->moduleName),
503
        ]);
504
    }
505
506
    /**
507
     * @param int $id
508
     * @return \Illuminate\View\View
509
     */
510 2
    public function restoreRevision($id)
511
    {
512 2
        if ($this->request->has('revisionId')) {
513 1
            $item = $this->repository->previewForRevision($id, $this->request->get('revisionId'));
514 1
            $item->id = $id;
0 ignored issues
show
Bug introduced by
The property id does not seem to exist on Illuminate\Database\Eloquent\Builder.
Loading history...
515 1
            $item->cmsRestoring = true;
0 ignored issues
show
Bug introduced by
The property cmsRestoring does not seem to exist on Illuminate\Database\Eloquent\Builder.
Loading history...
516
        } else {
517 1
            throw new NotFoundHttpException();
518
        }
519
520 1
        $this->setBackLink();
521
522 1
        $view = Collection::make([
523 1
            "$this->viewPrefix.form",
524 1
            "twill::$this->moduleName.form",
525 1
            "twill::layouts.form",
526
        ])->first(function ($view) {
527 1
            return View::exists($view);
528 1
        });
529
530 1
        $revision = $item->revisions()->where('id', $this->request->get('revisionId'))->first();
531 1
        $date = $revision->created_at->toDayDateTimeString();
0 ignored issues
show
Bug introduced by
The method toDayDateTimeString() does not exist on DateTime. It seems like you code against a sub-type of DateTime such as Carbon\Carbon. ( Ignorable by Annotation )

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

531
        /** @scrutinizer ignore-call */ 
532
        $date = $revision->created_at->toDayDateTimeString();
Loading history...
532
533 1
        Session::flash('restoreMessage', "You are currently editing an older revision of this content (saved by $revision->byUser on $date). Make changes if needed and click restore to save a new revision.");
0 ignored issues
show
Bug introduced by
The property byUser does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
534
535 1
        return View::make($view, $this->form($id, $item));
0 ignored issues
show
Bug introduced by
It seems like $item can also be of type Illuminate\Database\Eloquent\Builder; however, parameter $item of A17\Twill\Http\Controlle...oduleController::form() does only seem to accept A17\Twill\Models\Model|null, maybe add an additional type check? ( Ignorable by Annotation )

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

535
        return View::make($view, $this->form($id, /** @scrutinizer ignore-type */ $item));
Loading history...
536
    }
537
538
    /**
539
     * @return \Illuminate\Http\JsonResponse
540
     */
541 2
    public function publish()
542
    {
543
        try {
544 2
            if ($this->repository->updateBasic($this->request->get('id'), [
545 2
                'published' => !$this->request->get('active'),
546
            ])) {
547 2
                activity()->performedOn(
548 2
                    $this->repository->getById($this->request->get('id'))
549 1
                )->log(
550 1
                    ($this->request->get('active') ? 'un' : '') . 'published'
551
                );
552
553 1
                $this->fireEvent();
554
555 1
                return $this->respondWithSuccess(
556 1
                    $this->modelTitle . ' ' . ($this->request->get('active') ? 'un' : '') . 'published!'
557
                );
558
            }
559 1
        } catch (\Exception $e) {
560 1
            \Log::error($e);
561
        }
562
563 1
        return $this->respondWithError(
564 1
            $this->modelTitle . ' was not published. Something wrong happened!'
565
        );
566
    }
567
568
    /**
569
     * @return \Illuminate\Http\JsonResponse
570
     */
571
    public function bulkPublish()
572
    {
573
        try {
574
            if ($this->repository->updateBasic(explode(',', $this->request->get('ids')), [
575
                'published' => $this->request->get('publish'),
576
            ])) {
577
                $this->fireEvent();
578
579
                return $this->respondWithSuccess(
580
                    $this->modelTitle . ' items ' . ($this->request->get('publish') ? '' : 'un') . 'published!'
581
                );
582
            }
583
        } catch (\Exception $e) {
584
            \Log::error($e);
585
        }
586
587
        return $this->respondWithError(
588
            $this->modelTitle . ' items were not published. Something wrong happened!'
589
        );
590
    }
591
592
    /**
593
     * @param int $id
594
     * @param int|null $submoduleId
595
     * @return \Illuminate\Http\JsonResponse
596
     */
597 2
    public function destroy($id, $submoduleId = null)
598
    {
599 2
        $item = $this->repository->getById($submoduleId ?? $id);
600 2
        if ($this->repository->delete($submoduleId ?? $id)) {
601 2
            $this->fireEvent();
602 2
            activity()->performedOn($item)->log('deleted');
603 2
            return $this->respondWithSuccess($this->modelTitle . ' moved to trash!');
604
        }
605
606
        return $this->respondWithError($this->modelTitle . ' was not moved to trash. Something wrong happened!');
607
    }
608
609
    /**
610
     * @return \Illuminate\Http\JsonResponse
611
     */
612
    public function bulkDelete()
613
    {
614
        if ($this->repository->bulkDelete(explode(',', $this->request->get('ids')))) {
615
            $this->fireEvent();
616
            return $this->respondWithSuccess($this->modelTitle . ' items moved to trash!');
617
        }
618
619
        return $this->respondWithError($this->modelTitle . ' items were not moved to trash. Something wrong happened!');
620
    }
621
622
    /**
623
     * @return \Illuminate\Http\JsonResponse
624
     */
625
    public function forceDelete()
626
    {
627
        if ($this->repository->forceDelete($this->request->get('id'))) {
628
            $this->fireEvent();
629
            return $this->respondWithSuccess($this->modelTitle . ' destroyed!');
630
        }
631
632
        return $this->respondWithError($this->modelTitle . ' was not destroyed. Something wrong happened!');
633
    }
634
635
    /**
636
     * @return \Illuminate\Http\JsonResponse
637
     */
638
    public function bulkForceDelete()
639
    {
640
        if ($this->repository->bulkForceDelete(explode(',', $this->request->get('ids')))) {
641
            $this->fireEvent();
642
            return $this->respondWithSuccess($this->modelTitle . ' items destroyed!');
643
        }
644
645
        return $this->respondWithError($this->modelTitle . ' items were not destroyed. Something wrong happened!');
646
    }
647
648
    /**
649
     * @return \Illuminate\Http\JsonResponse
650
     */
651 2
    public function restore()
652
    {
653 2
        if ($this->repository->restore($this->request->get('id'))) {
654 1
            $this->fireEvent();
655 1
            activity()->performedOn($this->repository->getById($this->request->get('id')))->log('restored');
656 1
            return $this->respondWithSuccess($this->modelTitle . ' restored!');
657
        }
658
659 1
        return $this->respondWithError($this->modelTitle . ' was not restored. Something wrong happened!');
660
    }
661
662
    /**
663
     * @return \Illuminate\Http\JsonResponse
664
     */
665
    public function bulkRestore()
666
    {
667
        if ($this->repository->bulkRestore(explode(',', $this->request->get('ids')))) {
668
            $this->fireEvent();
669
            return $this->respondWithSuccess($this->modelTitle . ' items restored!');
670
        }
671
672
        return $this->respondWithError($this->modelTitle . ' items were not restored. Something wrong happened!');
673
    }
674
675
    /**
676
     * @return \Illuminate\Http\JsonResponse
677
     */
678 2
    public function feature()
679
    {
680 2
        if (($id = $this->request->get('id'))) {
681 2
            $featuredField = $this->request->get('featureField') ?? $this->featureField;
682 2
            $featured = !$this->request->get('active');
683
684 2
            if ($this->repository->isUniqueFeature()) {
685
                if ($featured) {
686
                    $this->repository->updateBasic(null, [$featuredField => false]);
687
                    $this->repository->updateBasic($id, [$featuredField => $featured]);
688
                }
689
            } else {
690 2
                $this->repository->updateBasic($id, [$featuredField => $featured]);
691
            }
692
693 2
            activity()->performedOn(
694 2
                $this->repository->getById($id)
695 1
            )->log(
696 1
                ($this->request->get('active') ? 'un' : '') . 'featured'
697
            );
698
699 1
            $this->fireEvent();
700 1
            return $this->respondWithSuccess($this->modelTitle . ' ' . ($this->request->get('active') ? 'un' : '') . 'featured!');
701
        }
702
703
        return $this->respondWithError($this->modelTitle . ' was not featured. Something wrong happened!');
704
    }
705
706
    /**
707
     * @return \Illuminate\Http\JsonResponse
708
     */
709
    public function bulkFeature()
710
    {
711
        if (($ids = explode(',', $this->request->get('ids')))) {
712
            $featuredField = $this->request->get('featureField') ?? $this->featureField;
713
            $featured = $this->request->get('feature') ?? true;
714
            // we don't need to check if unique feature since bulk operation shouldn't be allowed in this case
715
            $this->repository->updateBasic($ids, [$featuredField => $featured]);
716
            $this->fireEvent();
717
            return $this->respondWithSuccess($this->modelTitle . ' items ' . ($this->request->get('feature') ? '' : 'un') . 'featured!');
718
        }
719
720
        return $this->respondWithError($this->modelTitle . ' items were not featured. Something wrong happened!');
721
    }
722
723
    /**
724
     * @return \Illuminate\Http\JsonResponse
725
     */
726 2
    public function reorder()
727
    {
728 2
        if (($values = $this->request->get('ids')) && !empty($values)) {
729 2
            $this->repository->setNewOrder($values);
730 1
            $this->fireEvent();
731 1
            return $this->respondWithSuccess($this->modelTitle . ' order changed!');
732
        }
733
734
        return $this->respondWithError($this->modelTitle . ' order was not changed. Something wrong happened!');
735
    }
736
737
    /**
738
     * @return \Illuminate\Http\JsonResponse
739
     */
740 1
    public function tags()
741
    {
742 1
        $query = $this->request->input('q');
743 1
        $tags = $this->repository->getTags($query);
0 ignored issues
show
Bug introduced by
The method getTags() does not exist on A17\Twill\Repositories\ModuleRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

743
        /** @scrutinizer ignore-call */ 
744
        $tags = $this->repository->getTags($query);
Loading history...
744
745
        return Response::json(['items' => $tags->map(function ($tag) {
746
            return $tag->name;
747 1
        })], 200);
748
    }
749
750
    /**
751
     * @param array $prependScope
752
     * @return array
753
     */
754 6
    protected function getIndexData($prependScope = [])
755
    {
756 6
        $scopes = $this->filterScope($prependScope);
757 6
        $items = $this->getIndexItems($scopes);
758
759
        $data = [
760 6
            'tableData' => $this->getIndexTableData($items),
761 6
            'tableColumns' => $this->getIndexTableColumns($items),
762 6
            'tableMainFilters' => $this->getIndexTableMainFilters($items),
763 6
            'filters' => json_decode($this->request->get('filter'), true) ?? [],
764 6
            'hiddenFilters' => array_keys(Arr::except($this->filters, array_keys($this->defaultFilters))),
765 6
            'filterLinks' => $this->filterLinks ?? [],
766 6
            'maxPage' => method_exists($items, 'lastPage') ? $items->lastPage() : 1,
767 6
            'defaultMaxPage' => method_exists($items, 'total') ? ceil($items->total() / $this->perPage) : 1,
768 6
            'offset' => method_exists($items, 'perPage') ? $items->perPage() : count($items),
769 6
            'defaultOffset' => $this->perPage,
770 6
        ] + $this->getIndexUrls($this->moduleName, $this->routePrefix);
771
772 6
        $baseUrl = $this->getPermalinkBaseUrl();
773
774
        $options = [
775 6
            'moduleName' => $this->moduleName,
776 6
            'reorder' => $this->getIndexOption('reorder'),
777 6
            'create' => $this->getIndexOption('create'),
778 6
            'translate' => $this->moduleHas('translations'),
779 6
            'translateTitle' => $this->titleIsTranslatable(),
780 6
            'permalink' => $this->getIndexOption('permalink'),
781 6
            'bulkEdit' => $this->getIndexOption('bulkEdit'),
782 6
            'titleFormKey' => $this->titleFormKey ?? $this->titleColumnKey,
783 6
            'baseUrl' => $baseUrl,
784 6
            'permalinkPrefix' => $this->getPermalinkPrefix($baseUrl),
785
        ];
786
787 6
        return array_replace_recursive($data + $options, $this->indexData($this->request));
788
    }
789
790
    /**
791
     * @param Request $request
792
     * @return array
793
     */
794 5
    protected function indexData($request)
795
    {
796 5
        return [];
797
    }
798
799
    /**
800
     * @param array $scopes
801
     * @param bool $forcePagination
802
     * @return \Illuminate\Database\Eloquent\Collection
803
     */
804 12
    protected function getIndexItems($scopes = [], $forcePagination = false)
805
    {
806 12
        return $this->transformIndexItems($this->repository->get(
807 12
            $this->indexWith,
808
            $scopes,
809 12
            $this->orderScope(),
810 12
            $this->request->get('offset') ?? $this->perPage ?? 50,
811
            $forcePagination
812
        ));
813
    }
814
815
    /**
816
     * @param \Illuminate\Database\Eloquent\Collection $items
817
     * @return \Illuminate\Database\Eloquent\Collection
818
     */
819 10
    protected function transformIndexItems($items)
820
    {
821 10
        return $items;
822
    }
823
824
    /**
825
     * @param \Illuminate\Database\Eloquent\Collection $items
826
     * @return array
827
     */
828 6
    protected function getIndexTableData($items)
829
    {
830 6
        $translated = $this->moduleHas('translations');
831
        return $items->map(function ($item) use ($translated) {
832
            $columnsData = Collection::make($this->indexColumns)->mapWithKeys(function ($column) use ($item) {
833 3
                return $this->getItemColumnData($item, $column);
834 3
            })->toArray();
835
836 3
            $name = $columnsData[$this->titleColumnKey];
837
838 3
            if (empty($name)) {
839
                if ($this->moduleHas('translations')) {
840
                    $fallBackTranslation = $item->translations()->where('active', true)->first();
841
842
                    if (isset($fallBackTranslation->{$this->titleColumnKey})) {
843
                        $name = $fallBackTranslation->{$this->titleColumnKey};
844
                    }
845
                }
846
847
                $name = $name ?? ('Missing ' . $this->titleColumnKey);
848
            }
849
850 3
            unset($columnsData[$this->titleColumnKey]);
851
852 3
            $itemIsTrashed = method_exists($item, 'trashed') && $item->trashed();
853 3
            $itemCanDelete = $this->getIndexOption('delete') && ($item->canDelete ?? true);
854 3
            $canEdit = $this->getIndexOption('edit');
855
856 3
            return array_replace([
857 3
                'id' => $item->id,
858 3
                'name' => $name,
859 3
                'publish_start_date' => $item->publish_start_date,
860 3
                'publish_end_date' => $item->publish_end_date,
861 3
                'edit' => $canEdit ? $this->getModuleRoute($item->id, 'edit') : null,
862 3
                'delete' => $itemCanDelete ? $this->getModuleRoute($item->id, 'destroy') : null,
863 3
            ] + ($this->getIndexOption('editInModal') ? [
864 1
                'editInModal' => $this->getModuleRoute($item->id, 'edit'),
865 1
                'updateUrl' => $this->getModuleRoute($item->id, 'update'),
866 3
            ] : []) + ($this->getIndexOption('publish') && ($item->canPublish ?? true) ? [
867 3
                'published' => $item->published,
868 3
            ] : []) + ($this->getIndexOption('feature') && ($item->canFeature ?? true) ? [
869
                'featured' => $item->{$this->featureField},
870 3
            ] : []) + (($this->getIndexOption('restore') && $itemIsTrashed) ? [
871
                'deleted' => true,
872 3
            ] : []) + ($translated ? [
873 3
                'languages' => $item->getActiveLanguages(),
874 3
            ] : []) + $columnsData, $this->indexItemData($item));
875 6
        })->toArray();
876
    }
877
878
    /**
879
     * @param \A17\Twill\Models\Model $item
880
     * @return array
881
     */
882 2
    protected function indexItemData($item)
883
    {
884 2
        return [];
885
    }
886
887
    /**
888
     * @param \A17\Twill\Models\Model $item
889
     * @param array $column
890
     * @return array
891
     */
892 5
    protected function getItemColumnData($item, $column)
893
    {
894 5
        if (isset($column['thumb']) && $column['thumb']) {
895 2
            if (isset($column['present']) && $column['present']) {
896
                return [
897
                    'thumbnail' => $item->presentAdmin()->{$column['presenter']},
898
                ];
899
            } else {
900 2
                $variant = isset($column['variant']);
901 2
                $role = $variant ? $column['variant']['role'] : head(array_keys($item->mediasParams));
0 ignored issues
show
Bug introduced by
The property mediasParams does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
902 2
                $crop = $variant ? $column['variant']['crop'] : head(array_keys(head($item->mediasParams)));
903 2
                $params = $variant && isset($column['variant']['params'])
904
                ? $column['variant']['params']
905 2
                : ['w' => 80, 'h' => 80, 'fit' => 'crop'];
906
907
                return [
908 2
                    'thumbnail' => $item->cmsImage($role, $crop, $params),
909
                ];
910
            }
911
        }
912
913 5
        if (isset($column['nested']) && $column['nested']) {
914
            $field = $column['nested'];
915
            $nestedCount = $item->{$column['nested']}->count();
916
            $value = '<a href="';
917
            $value .= moduleRoute("$this->moduleName.$field", $this->routePrefix, 'index', [$item->id]);
918
            $value .= '">' . $nestedCount . " " . (strtolower($nestedCount > 1
919
                ? Str::plural($column['title'])
920
                : Str::singular($column['title']))) . '</a>';
921
        } else {
922 5
            $field = $column['field'];
923 5
            $value = $item->$field;
924
        }
925
926 5
        if (isset($column['relationship'])) {
927
            $field = $column['relationship'] . ucfirst($column['field']);
928
            $value = Arr::get($item, "{$column['relationship']}.{$column['field']}");
929 5
        } elseif (isset($column['present']) && $column['present']) {
930
            $value = $item->presentAdmin()->{$column['field']};
931
        }
932
933
        return [
934 5
            "$field" => $value,
935
        ];
936
    }
937
938
    /**
939
     * @param \Illuminate\Database\Eloquent\Collection $items
940
     * @return array
941
     */
942 6
    protected function getIndexTableColumns($items)
0 ignored issues
show
Unused Code introduced by
The parameter $items is not used and could be removed. ( Ignorable by Annotation )

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

942
    protected function getIndexTableColumns(/** @scrutinizer ignore-unused */ $items)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
943
    {
944 6
        $tableColumns = [];
945 6
        $visibleColumns = $this->request->get('columns') ?? false;
946
947 6
        if (isset(Arr::first($this->indexColumns)['thumb'])
948 6
            && Arr::first($this->indexColumns)['thumb']
949
        ) {
950 4
            array_push($tableColumns, [
951 4
                'name' => 'thumbnail',
952 4
                'label' => 'Thumbnail',
953 4
                'visible' => $visibleColumns ? in_array('thumbnail', $visibleColumns) : true,
954
                'optional' => true,
955
                'sortable' => false,
956
            ]);
957 4
            array_shift($this->indexColumns);
958
        }
959
960 6
        if ($this->getIndexOption('feature')) {
961
            array_push($tableColumns, [
962
                'name' => 'featured',
963
                'label' => 'Featured',
964
                'visible' => true,
965
                'optional' => false,
966
                'sortable' => false,
967
            ]);
968
        }
969
970 6
        if ($this->getIndexOption('publish')) {
971 6
            array_push($tableColumns, [
972 6
                'name' => 'published',
973
                'label' => 'Published',
974
                'visible' => true,
975
                'optional' => false,
976
                'sortable' => false,
977
            ]);
978
        }
979
980 6
        array_push($tableColumns, [
981 6
            'name' => 'name',
982 6
            'label' => $this->indexColumns[$this->titleColumnKey]['title'] ?? 'Name',
983
            'visible' => true,
984
            'optional' => false,
985 6
            'sortable' => $this->getIndexOption('reorder') ? false : ($this->indexColumns[$this->titleColumnKey]['sort'] ?? false),
986
        ]);
987
988 6
        unset($this->indexColumns[$this->titleColumnKey]);
989
990 6
        foreach ($this->indexColumns as $column) {
991 4
            $columnName = isset($column['relationship'])
992
            ? $column['relationship'] . ucfirst($column['field'])
993 4
            : (isset($column['nested']) ? $column['nested'] : $column['field']);
994
995 4
            array_push($tableColumns, [
996 4
                'name' => $columnName,
997 4
                'label' => $column['title'],
998 4
                'visible' => $visibleColumns ? in_array($columnName, $visibleColumns) : ($column['visible'] ?? true),
999 4
                'optional' => $column['optional'] ?? true,
1000 4
                'sortable' => $this->getIndexOption('reorder') ? false : ($column['sort'] ?? false),
1001 4
                'html' => $column['html'] ?? false,
1002
            ]);
1003
        }
1004
1005 6
        if ($this->moduleHas('translations')) {
1006 5
            array_push($tableColumns, [
1007 5
                'name' => 'languages',
1008 5
                'label' => twillTrans('twill::lang.listing.languages'),
1009 5
                'visible' => $visibleColumns ? in_array('languages', $visibleColumns) : true,
1010
                'optional' => true,
1011
                'sortable' => false,
1012
            ]);
1013
        }
1014
1015 6
        return $tableColumns;
1016
    }
1017
1018
    /**
1019
     * @param \Illuminate\Database\Eloquent\Collection $items
1020
     * @param array $scopes
1021
     * @return array
1022
     */
1023 5
    protected function getIndexTableMainFilters($items, $scopes = [])
1024
    {
1025 5
        $statusFilters = [];
1026
1027 5
        $scope = ($this->submodule ? [
1028
            $this->getParentModuleForeignKey() => $this->submoduleParentId,
1029 5
        ] : []) + $scopes;
1030
1031 5
        array_push($statusFilters, [
1032 5
            'name' => twillTrans('twill::lang.listing.filter.all-items'),
1033 5
            'slug' => 'all',
1034 5
            'number' => $this->repository->getCountByStatusSlug('all', $scope),
1035
        ]);
1036
1037 5
        if ($this->moduleHas('revisions') && $this->getIndexOption('create')) {
1038 5
            array_push($statusFilters, [
1039 5
                'name' => twillTrans('twill::lang.listing.filter.mine'),
1040 5
                'slug' => 'mine',
1041 5
                'number' => $this->repository->getCountByStatusSlug('mine', $scope),
1042
            ]);
1043
        }
1044
1045 5
        if ($this->getIndexOption('publish')) {
1046 5
            array_push($statusFilters, [
1047 5
                'name' => twillTrans('twill::lang.listing.filter.published'),
1048 5
                'slug' => 'published',
1049 5
                'number' => $this->repository->getCountByStatusSlug('published', $scope),
1050
            ], [
1051 5
                'name' => twillTrans('twill::lang.listing.filter.draft'),
1052 5
                'slug' => 'draft',
1053 5
                'number' => $this->repository->getCountByStatusSlug('draft', $scope),
1054
            ]);
1055
        }
1056
1057 5
        if ($this->getIndexOption('restore')) {
1058 5
            array_push($statusFilters, [
1059 5
                'name' => twillTrans('twill::lang.listing.filter.trash'),
1060 5
                'slug' => 'trash',
1061 5
                'number' => $this->repository->getCountByStatusSlug('trash', $scope),
1062
            ]);
1063
        }
1064
1065 5
        return $statusFilters;
1066
    }
1067
1068
    /**
1069
     * @param string $moduleName
1070
     * @param string $routePrefix
1071
     * @return array
1072
     */
1073 6
    protected function getIndexUrls($moduleName, $routePrefix)
0 ignored issues
show
Unused Code introduced by
The parameter $routePrefix is not used and could be removed. ( Ignorable by Annotation )

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

1073
    protected function getIndexUrls($moduleName, /** @scrutinizer ignore-unused */ $routePrefix)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $moduleName is not used and could be removed. ( Ignorable by Annotation )

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

1073
    protected function getIndexUrls(/** @scrutinizer ignore-unused */ $moduleName, $routePrefix)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1074
    {
1075 6
        return Collection::make([
1076 6
            'store',
1077
            'publish',
1078
            'bulkPublish',
1079
            'restore',
1080
            'bulkRestore',
1081
            'forceDelete',
1082
            'bulkForceDelete',
1083
            'reorder',
1084
            'feature',
1085
            'bulkFeature',
1086
            'bulkDelete',
1087
        ])->mapWithKeys(function ($endpoint) {
1088
            return [
1089 6
                $endpoint . 'Url' => $this->getIndexOption($endpoint) ? moduleRoute(
1090 6
                    $this->moduleName, $this->routePrefix, $endpoint,
1091 6
                    $this->submodule ? [$this->submoduleParentId] : []
1092
                ) : null,
1093
            ];
1094 6
        })->toArray();
1095
    }
1096
1097
    /**
1098
     * @param string $option
1099
     * @return bool
1100
     */
1101 29
    protected function getIndexOption($option)
1102
    {
1103
        return once(function () use ($option) {
1104
            $customOptionNamesMapping = [
1105 29
                'store' => 'create',
1106
            ];
1107
1108 29
            $option = array_key_exists($option, $customOptionNamesMapping) ? $customOptionNamesMapping[$option] : $option;
1109
1110
            $authorizableOptions = [
1111 29
                'create' => 'edit',
1112
                'edit' => 'edit',
1113
                'publish' => 'publish',
1114
                'feature' => 'feature',
1115
                'reorder' => 'reorder',
1116
                'delete' => 'delete',
1117
                'restore' => 'delete',
1118
                'forceDelete' => 'delete',
1119
                'bulkForceDelete' => 'delete',
1120
                'bulkPublish' => 'publish',
1121
                'bulkRestore' => 'delete',
1122
                'bulkFeature' => 'feature',
1123
                'bulkDelete' => 'delete',
1124
                'bulkEdit' => 'edit',
1125
                'editInModal' => 'edit',
1126
            ];
1127
1128 29
            $authorized = array_key_exists($option, $authorizableOptions) ? Auth::guard('twill_users')->user()->can($authorizableOptions[$option]) : true;
1129 29
            return ($this->indexOptions[$option] ?? $this->defaultIndexOptions[$option] ?? false) && $authorized;
1130 29
        });
1131
    }
1132
1133
    /**
1134
     * @param array $prependScope
1135
     * @return array
1136
     */
1137 2
    protected function getBrowserData($prependScope = [])
1138
    {
1139 2
        if ($this->request->has('except')) {
1140
            $prependScope['exceptIds'] = $this->request->get('except');
1141
        }
1142
1143 2
        $scopes = $this->filterScope($prependScope);
1144 2
        $items = $this->getBrowserItems($scopes);
1145 2
        $data = $this->getBrowserTableData($items);
1146
1147 2
        return array_replace_recursive(['data' => $data], $this->indexData($this->request));
1148
    }
1149
1150
    /**
1151
     * @param \Illuminate\Database\Eloquent\Collection $items
1152
     * @return array
1153
     */
1154 2
    protected function getBrowserTableData($items)
1155
    {
1156 2
        $withImage = $this->moduleHas('medias');
1157
1158
        return $items->map(function ($item) use ($withImage) {
1159
            $columnsData = Collection::make($this->browserColumns)->mapWithKeys(function ($column) use ($item) {
1160 2
                return $this->getItemColumnData($item, $column);
1161 2
            })->toArray();
1162
1163 2
            $name = $columnsData[$this->titleColumnKey];
1164 2
            unset($columnsData[$this->titleColumnKey]);
1165
1166
            return [
1167 2
                'id' => $item->id,
1168 2
                'name' => $name,
1169 2
                'edit' => moduleRoute($this->moduleName, $this->routePrefix, 'edit', $item->id),
1170 2
                'endpointType' => $this->repository->getMorphClass(),
0 ignored issues
show
Bug introduced by
The method getMorphClass() does not exist on A17\Twill\Repositories\ModuleRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

1170
                'endpointType' => $this->repository->/** @scrutinizer ignore-call */ getMorphClass(),
Loading history...
1171 2
            ] + $columnsData + ($withImage && !array_key_exists('thumbnail', $columnsData) ? [
1172 2
                'thumbnail' => $item->defaultCmsImage(['w' => 100, 'h' => 100]),
1173 2
            ] : []);
1174 2
        })->toArray();
1175
    }
1176
1177
    /**
1178
     * @param array $scopes
1179
     * @return \Illuminate\Database\Eloquent\Collection
1180
     */
1181 2
    protected function getBrowserItems($scopes = [])
1182
    {
1183 2
        return $this->getIndexItems($scopes, true);
1184
    }
1185
1186
    /**
1187
     * @param array $prepend
1188
     * @return array
1189
     */
1190 12
    protected function filterScope($prepend = [])
1191
    {
1192 12
        $scope = [];
1193
1194 12
        $requestFilters = $this->getRequestFilters();
1195
1196 12
        $this->filters = array_merge($this->filters, $this->defaultFilters);
1197
1198 12
        if (array_key_exists('status', $requestFilters)) {
1199 1
            switch ($requestFilters['status']) {
1200 1
                case 'published':
1201 1
                    $scope['published'] = true;
1202 1
                    break;
1203
                case 'draft':
1204
                    $scope['draft'] = true;
1205
                    break;
1206
                case 'trash':
1207
                    $scope['onlyTrashed'] = true;
1208
                    break;
1209
                case 'mine':
1210
                    $scope['mine'] = true;
1211
                    break;
1212
            }
1213
1214 1
            unset($requestFilters['status']);
1215
        }
1216
1217 12
        foreach ($this->filters as $key => $field) {
1218 12
            if (array_key_exists($key, $requestFilters)) {
1219 2
                $value = $requestFilters[$key];
1220 2
                if ($value == 0 || !empty($value)) {
1221
                    // add some syntaxic sugar to scope the same filter on multiple columns
1222 2
                    $fieldSplitted = explode('|', $field);
1223 2
                    if (count($fieldSplitted) > 1) {
1224
                        $requestValue = $requestFilters[$key];
1225
                        Collection::make($fieldSplitted)->each(function ($scopeKey) use (&$scope, $requestValue) {
1226
                            $scope[$scopeKey] = $requestValue;
1227
                        });
1228
                    } else {
1229 2
                        $scope[$field] = $requestFilters[$key];
1230
                    }
1231
                }
1232
            }
1233
        }
1234
1235 12
        return $prepend + $scope;
1236
    }
1237
1238
    /**
1239
     * @return array
1240
     */
1241 7
    protected function getRequestFilters()
1242
    {
1243 7
        if ($this->request->has('search')) {
1244
            return ['search' => $this->request->get('search')];
1245
        }
1246
1247 7
        return json_decode($this->request->get('filter'), true) ?? [];
1248
    }
1249
1250
    /**
1251
     * @return void
1252
     */
1253 40
    protected function applyFiltersDefaultOptions()
1254
    {
1255 40
        if (!count($this->filtersDefaultOptions) || $this->request->has('search')) {
1256 40
            return;
1257
        }
1258
1259
        $filters = $this->getRequestFilters();
1260
1261
        foreach ($this->filtersDefaultOptions as $filterName => $defaultOption) {
1262
            if (!isset($filters[$filterName])) {
1263
                $filters[$filterName] = $defaultOption;
1264
            }
1265
        }
1266
1267
        $this->request->merge(['filter' => json_encode($filters)]);
1268
    }
1269
1270
    /**
1271
     * @return array
1272
     */
1273 12
    protected function orderScope()
1274
    {
1275 12
        $orders = [];
1276 12
        if ($this->request->has('sortKey') && $this->request->has('sortDir')) {
1277 1
            if (($key = $this->request->get('sortKey')) == 'name') {
1278
                $sortKey = $this->titleColumnKey;
1279 1
            } elseif (!empty($key)) {
1280 1
                $sortKey = $key;
1281
            }
1282
1283 1
            if (isset($sortKey)) {
1284 1
                $orders[$this->indexColumns[$sortKey]['sortKey'] ?? $sortKey] = $this->request->get('sortDir');
1285
            }
1286
        }
1287
1288
        // don't apply default orders if reorder is enabled
1289 12
        $reorder = $this->getIndexOption('reorder');
1290 12
        $defaultOrders = ($reorder ? [] : ($this->defaultOrders ?? []));
1291
1292 12
        return $orders + $defaultOrders;
1293
    }
1294
1295
    /**
1296
     * @param int $id
1297
     * @param \A17\Twill\Models\Model|null $item
1298
     * @return array
1299
     */
1300 4
    protected function form($id, $item = null)
1301
    {
1302 4
        $item = $item ?? $this->repository->getById($id, $this->formWith, $this->formWithCount);
1303
1304 4
        $fullRoutePrefix = 'admin.' . ($this->routePrefix ? $this->routePrefix . '.' : '') . $this->moduleName . '.';
1305 4
        $previewRouteName = $fullRoutePrefix . 'preview';
1306 4
        $restoreRouteName = $fullRoutePrefix . 'restoreRevision';
1307
1308 4
        $baseUrl = $item->urlWithoutSlug ?? $this->getPermalinkBaseUrl();
0 ignored issues
show
Bug introduced by
The property urlWithoutSlug does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
1309
1310
        $data = [
1311 4
            'item' => $item,
1312 4
            'moduleName' => $this->moduleName,
1313 4
            'routePrefix' => $this->routePrefix,
1314 4
            'titleFormKey' => $this->titleFormKey ?? $this->titleColumnKey,
1315 4
            'publish' => $item->canPublish ?? true,
0 ignored issues
show
Bug introduced by
The property canPublish does not seem to exist on A17\Twill\Models\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
1316 4
            'translate' => $this->moduleHas('translations'),
1317 4
            'permalink' => $this->getIndexOption('permalink'),
1318 4
            'form_fields' => $this->repository->getFormFields($item),
1319 4
            'baseUrl' => $baseUrl,
1320 4
            'permalinkPrefix' => $this->getPermalinkPrefix($baseUrl),
1321 4
            'saveUrl' => $this->getModuleRoute($item->id, 'update'),
1322 4
            'editor' => $this->moduleHas('revisions') && $this->moduleHas('blocks') && !$this->disableEditor,
1323 4
            'blockPreviewUrl' => Route::has('admin.blocks.preview') ? URL::route('admin.blocks.preview') : '#',
1324 4
            'revisions' => $this->moduleHas('revisions') ? $item->revisionsArray() : null,
1325 4
        ] + (Route::has($previewRouteName) ? [
1326 4
            'previewUrl' => moduleRoute($this->moduleName, $this->routePrefix, 'preview', $item->id),
0 ignored issues
show
Bug introduced by
$item->id of type integer is incompatible with the type array expected by parameter $parameters of moduleRoute(). ( Ignorable by Annotation )

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

1326
            'previewUrl' => moduleRoute($this->moduleName, $this->routePrefix, 'preview', /** @scrutinizer ignore-type */ $item->id),
Loading history...
1327 4
        ] : [])
1328 4
             + (Route::has($restoreRouteName) ? [
1329 4
            'restoreUrl' => moduleRoute($this->moduleName, $this->routePrefix, 'restoreRevision', $item->id),
1330 4
        ] : []);
1331
1332 4
        return array_replace_recursive($data, $this->formData($this->request));
1333
    }
1334
1335
    /**
1336
     * @param int $id
1337
     * @return array
1338
     */
1339 1
    protected function modalFormData($id)
1340
    {
1341 1
        $item = $this->repository->getById($id, $this->formWith, $this->formWithCount);
1342 1
        $fields = $this->repository->getFormFields($item);
1343 1
        $data = [];
1344
1345 1
        if ($this->moduleHas('translations') && isset($fields['translations'])) {
1346 1
            foreach ($fields['translations'] as $fieldName => $fieldValue) {
1347 1
                $data['fields'][] = [
1348 1
                    'name' => $fieldName,
1349 1
                    'value' => $fieldValue,
1350
                ];
1351
            }
1352
1353 1
            $data['languages'] = $item->getActiveLanguages();
1354
1355 1
            unset($fields['translations']);
1356
        }
1357
1358 1
        foreach ($fields as $fieldName => $fieldValue) {
1359 1
            $data['fields'][] = [
1360 1
                'name' => $fieldName,
1361 1
                'value' => $fieldValue,
1362
            ];
1363
        }
1364
1365 1
        return array_replace_recursive($data, $this->formData($this->request));
1366
    }
1367
1368
    /**
1369
     * @param Request $request
1370
     * @return array
1371
     */
1372 4
    protected function formData($request)
1373
    {
1374 4
        return [];
1375
    }
1376
1377
    /**
1378
     * @param Request $item
1379
     * @return array
1380
     */
1381 1
    protected function previewData($item)
0 ignored issues
show
Unused Code introduced by
The parameter $item is not used and could be removed. ( Ignorable by Annotation )

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

1381
    protected function previewData(/** @scrutinizer ignore-unused */ $item)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1382
    {
1383 1
        return [];
1384
    }
1385
1386
    /**
1387
     * @return \A17\Twill\Http\Requests\Admin\Request
1388
     */
1389 21
    protected function validateFormRequest()
1390
    {
1391
        $unauthorizedFields = Collection::make($this->fieldsPermissions)->filter(function ($permission, $field) {
0 ignored issues
show
Unused Code introduced by
The parameter $field is not used and could be removed. ( Ignorable by Annotation )

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

1391
        $unauthorizedFields = Collection::make($this->fieldsPermissions)->filter(function ($permission, /** @scrutinizer ignore-unused */ $field) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1392 4
            return Auth::guard('twill_users')->user()->cannot($permission);
1393 21
        })->keys();
1394
1395
        $unauthorizedFields->each(function ($field) {
1396
            $this->request->offsetUnset($field);
1397 21
        });
1398
1399 21
        return App::make("$this->namespace\Http\Requests\Admin\\" . $this->modelName . "Request");
1400
    }
1401
1402
    /**
1403
     * @return string
1404
     */
1405 40
    protected function getNamespace()
1406
    {
1407 40
        return $this->namespace ?? Config::get('twill.namespace');
1408
    }
1409
1410
    /**
1411
     * @return string
1412
     */
1413 40
    protected function getRoutePrefix()
1414
    {
1415 40
        if ($this->request->route() != null) {
1416 39
            $routePrefix = ltrim(str_replace(Config::get('twill.admin_app_path'), '', $this->request->route()->getPrefix()), "/");
1417 39
            return str_replace("/", ".", $routePrefix);
1418
        }
1419
1420 1
        return '';
1421
    }
1422
1423
    /**
1424
     * @return string
1425
     */
1426 40
    protected function getModelName()
1427
    {
1428 40
        return $this->modelName ?? ucfirst(Str::singular($this->moduleName));
1429
    }
1430
1431
    /**
1432
     * @return \A17\Twill\Repositories\ModuleRepository
1433
     */
1434 40
    protected function getRepository()
1435
    {
1436 40
        return App::make("$this->namespace\Repositories\\" . $this->modelName . "Repository");
1437
    }
1438
1439
    /**
1440
     * @return string
1441
     */
1442 40
    protected function getViewPrefix()
1443
    {
1444 40
        return "admin.$this->moduleName";
1445
    }
1446
1447
    /**
1448
     * @return string
1449
     */
1450 40
    protected function getModelTitle()
1451
    {
1452 40
        return camelCaseToWords($this->modelName);
1453
    }
1454
1455
    /**
1456
     * @return string
1457
     */
1458
    protected function getParentModuleForeignKey()
1459
    {
1460
        return Str::singular(explode('.', $this->moduleName)[0]) . '_id';
1461
    }
1462
1463
    /**
1464
     * @return string
1465
     */
1466 10
    protected function getPermalinkBaseUrl()
1467
    {
1468 10
        return $this->request->getScheme() . '://' . Config::get('app.url') . '/'
1469 10
            . ($this->moduleHas('translations') ? '{language}/' : '')
1470 10
            . ($this->moduleHas('revisions') ? '{preview}/' : '')
1471 10
            . ($this->permalinkBase ?? $this->moduleName)
1472 10
            . (isset($this->permalinkBase) && empty($this->permalinkBase) ? '' : '/');
1473
    }
1474
1475
    /**
1476
     * @param string $baseUrl
1477
     * @return string
1478
     */
1479 10
    protected function getPermalinkPrefix($baseUrl)
1480
    {
1481 10
        return rtrim(str_replace(['http://', 'https://', '{preview}/', '{language}/'], '', $baseUrl), "/") . '/';
1482
    }
1483
1484
    /**
1485
     * @param int $id
1486
     * @param string $action
1487
     * @return string
1488
     */
1489 7
    protected function getModuleRoute($id, $action)
1490
    {
1491 7
        return moduleRoute(
1492 7
            $this->moduleName,
1493 7
            $this->routePrefix,
1494
            $action,
1495 7
            array_merge($this->submodule ? [$this->submoduleParentId] : [], [$id])
1496
        );
1497
    }
1498
1499
    /**
1500
     * @param string $behavior
1501
     * @return bool
1502
     */
1503 29
    protected function moduleHas($behavior)
1504
    {
1505 29
        return $this->repository->hasBehavior($behavior);
1506
    }
1507
1508
    /**
1509
     * @return bool
1510
     */
1511 6
    protected function titleIsTranslatable()
1512
    {
1513 6
        return $this->repository->isTranslatable(
1514 6
            $this->titleColumnKey
1515
        );
1516
    }
1517
1518
    /**
1519
     * @param string|null $back_link
1520
     * @param array $params
1521
     * @return void
1522
     */
1523 4
    protected function setBackLink($back_link = null, $params = [])
1524
    {
1525 4
        if (!isset($back_link)) {
1526 4
            if (($back_link = Session::get($this->getBackLinkSessionKey())) == null) {
1527 4
                $back_link = $this->request->headers->get('referer') ?? moduleRoute(
1528 4
                    $this->moduleName,
1529 4
                    $this->routePrefix,
1530 4
                    'index',
1531
                    $params
1532
                );
1533
            }
1534
        }
1535
1536 4
        if (!Session::get($this->moduleName . '_retain')) {
1537 1
            Session::put($this->getBackLinkSessionKey(), $back_link);
1538
        } else {
1539 3
            Session::put($this->moduleName . '_retain', false);
1540
        }
1541 4
    }
1542
1543
    /**
1544
     * @param string|null $fallback
1545
     * @param array $params
1546
     * @return string
1547
     */
1548
    protected function getBackLink($fallback = null, $params = [])
1549
    {
1550
        $back_link = Session::get($this->getBackLinkSessionKey(), $fallback);
1551
        return $back_link ?? moduleRoute($this->moduleName, $this->routePrefix, 'index', $params);
1552
    }
1553
1554
    /**
1555
     * @return string
1556
     */
1557 4
    protected function getBackLinkSessionKey()
1558
    {
1559 4
        return $this->moduleName . ($this->submodule ? $this->submoduleParentId ?? '' : '') . '_back_link';
1560
    }
1561
1562
    /**
1563
     * @param int $id
1564
     * @param array $params
1565
     * @return \Illuminate\Http\RedirectResponse
1566
     */
1567 1
    protected function redirectToForm($id, $params = [])
1568
    {
1569 1
        Session::put($this->moduleName . '_retain', true);
1570
1571 1
        return Redirect::to(moduleRoute(
1572 1
            $this->moduleName,
1573 1
            $this->routePrefix,
1574 1
            'edit',
1575 1
            array_filter($params) + [Str::singular($this->moduleName) => $id]
1576
        ));
1577
    }
1578
1579
    /**
1580
     * @param string $message
1581
     * @return \Illuminate\Http\JsonResponse
1582
     */
1583 8
    protected function respondWithSuccess($message)
1584
    {
1585 8
        return $this->respondWithJson($message, FlashLevel::SUCCESS);
1586
    }
1587
1588
    /**
1589
     * @param string $redirectUrl
1590
     * @return \Illuminate\Http\JsonResponse
1591
     */
1592 19
    protected function respondWithRedirect($redirectUrl)
1593
    {
1594 19
        return Response::json([
1595 19
            'redirect' => $redirectUrl,
1596
        ]);
1597
    }
1598
1599
    /**
1600
     * @param string $message
1601
     * @return \Illuminate\Http\JsonResponse
1602
     */
1603 2
    protected function respondWithError($message)
1604
    {
1605 2
        return $this->respondWithJson($message, FlashLevel::ERROR);
1606
    }
1607
1608
    /**
1609
     * @param string $message
1610
     * @param mixed $variant
1611
     * @return \Illuminate\Http\JsonResponse
1612
     */
1613 10
    protected function respondWithJson($message, $variant)
1614
    {
1615 10
        return Response::json([
1616 10
            'message' => $message,
1617 10
            'variant' => $variant,
1618
        ]);
1619
    }
1620
1621
    /**
1622
     * @param array $input
1623
     * @return void
1624
     */
1625 21
    protected function fireEvent($input = [])
1626
    {
1627 21
        fireCmsEvent('cms-module.saved', $input);
1628 21
    }
1629
}
1630