Passed
Push — feature/duplication ( 011e93 )
by
unknown
11:47
created

ModuleController::duplicate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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

428
            /** @scrutinizer ignore-call */ 
429
            $item = $this->repository->previewForRevision($id, $this->request->get('revisionId'));
Loading history...
429
        } else {
430
            $formRequest = $this->validateFormRequest();
431
            $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

431
            /** @scrutinizer ignore-call */ 
432
            $item = $this->repository->preview($id, $formRequest->all());
Loading history...
432
        }
433
434
        if ($this->request->has('activeLanguage')) {
435
            App::setLocale($this->request->get('activeLanguage'));
436
        }
437
438
        $previewView = $this->previewView ?? (Config::get('twill.frontend.views_path', 'site') . '.' . Str::singular($this->moduleName));
0 ignored issues
show
Bug Best Practice introduced by
The property previewView does not exist on A17\Twill\Http\Controllers\Admin\ModuleController. Did you maybe forget to declare it?
Loading history...
439
440
        return View::exists($previewView) ? View::make($previewView, array_replace([
441
            'item' => $item,
442
        ], $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

442
        ], $this->previewData(/** @scrutinizer ignore-type */ $item))) : View::make('twill::errors.preview', [
Loading history...
443
            'moduleName' => Str::singular($this->moduleName),
444
        ]);
445
    }
446
447
    /**
448
     * @param int $id
449
     * @return \Illuminate\View\View
450
     */
451
    public function restoreRevision($id)
452
    {
453
        if ($this->request->has('revisionId')) {
454
            $item = $this->repository->previewForRevision($id, $this->request->get('revisionId'));
455
            $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...
456
            $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...
457
        } else {
458
            throw new NotFoundHttpException();
459
        }
460
461
        $this->setBackLink();
462
463
        $view = Collection::make([
464
            "$this->viewPrefix.form",
465
            "twill::$this->moduleName.form",
466
            "twill::layouts.form",
467
        ])->first(function ($view) {
468
            return View::exists($view);
469
        });
470
471
        $revision = $item->revisions()->where('id', $this->request->get('revisionId'))->first();
472
        $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

472
        /** @scrutinizer ignore-call */ 
473
        $date = $revision->created_at->toDayDateTimeString();
Loading history...
473
474
        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...
475
476
        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

476
        return View::make($view, $this->form($id, /** @scrutinizer ignore-type */ $item));
Loading history...
477
    }
478
479
    /**
480
     * @return \Illuminate\Http\JsonResponse
481
     */
482
    public function publish()
483
    {
484
        try {
485
            if ($this->repository->updateBasic($this->request->get('id'), [
486
                'published' => !$this->request->get('active'),
487
            ])) {
488
                activity()->performedOn(
489
                    $this->repository->getById($this->request->get('id'))
490
                )->log(
491
                    ($this->request->get('active') ? 'un' : '') . 'published'
492
                );
493
494
                $this->fireEvent();
495
496
                return $this->respondWithSuccess(
497
                    $this->modelTitle . ' ' . ($this->request->get('active') ? 'un' : '') . 'published!'
498
                );
499
            }
500
        } catch (\Exception $e) {
501
            \Log::error($e);
502
        }
503
504
        return $this->respondWithError(
505
            $this->modelTitle . ' was not published. Something wrong happened!'
506
        );
507
    }
508
509
    /**
510
     * @return \Illuminate\Http\JsonResponse
511
     */
512
    public function bulkPublish()
513
    {
514
        try {
515
            if ($this->repository->updateBasic(explode(',', $this->request->get('ids')), [
516
                'published' => $this->request->get('publish'),
517
            ])) {
518
                $this->fireEvent();
519
520
                return $this->respondWithSuccess(
521
                    $this->modelTitle . ' items ' . ($this->request->get('publish') ? '' : 'un') . 'published!'
522
                );
523
            }
524
        } catch (\Exception $e) {
525
            \Log::error($e);
526
        }
527
528
        return $this->respondWithError(
529
            $this->modelTitle . ' items were not published. Something wrong happened!'
530
        );
531
    }
532
533
    /**
534
     * @param int $id
535
     * @param int|null $submoduleId
536
     * @return \Illuminate\Http\JsonResponse
537
     */
538
    public function duplicate($id, $submoduleId = null)
539
    {
540
541
        $item = $this->repository->getById($submoduleId ?? $id);
542
        if ($this->repository->duplicate($submoduleId ?? $id)) {
543
            $this->fireEvent();
544
            activity()->performedOn($item)->log('duplicated');
545
            return $this->respondWithSuccess($this->modelTitle . ' duplicated!');
546
        }
547
548
        return $this->respondWithError($this->modelTitle . ' was not duplicated. Something wrong happened!');
549
    }
550
551
    /**
552
     * @param int $id
553
     * @param int|null $submoduleId
554
     * @return \Illuminate\Http\JsonResponse
555
     */
556
    public function destroy($id, $submoduleId = null)
557
    {
558
        $item = $this->repository->getById($submoduleId ?? $id);
559
        if ($this->repository->delete($submoduleId ?? $id)) {
560
            $this->fireEvent();
561
            activity()->performedOn($item)->log('deleted');
562
            return $this->respondWithSuccess($this->modelTitle . ' moved to trash!');
563
        }
564
565
        return $this->respondWithError($this->modelTitle . ' was not moved to trash. Something wrong happened!');
566
    }
567
568
    /**
569
     * @return \Illuminate\Http\JsonResponse
570
     */
571
    public function bulkDelete()
572
    {
573
        if ($this->repository->bulkDelete(explode(',', $this->request->get('ids')))) {
574
            $this->fireEvent();
575
            return $this->respondWithSuccess($this->modelTitle . ' items moved to trash!');
576
        }
577
578
        return $this->respondWithError($this->modelTitle . ' items were not moved to trash. Something wrong happened!');
579
    }
580
581
    /**
582
     * @return \Illuminate\Http\JsonResponse
583
     */
584
    public function restore()
585
    {
586
        if ($this->repository->restore($this->request->get('id'))) {
587
            $this->fireEvent();
588
            activity()->performedOn($this->repository->getById($this->request->get('id')))->log('restored');
589
            return $this->respondWithSuccess($this->modelTitle . ' restored!');
590
        }
591
592
        return $this->respondWithError($this->modelTitle . ' was not restored. Something wrong happened!');
593
    }
594
595
    /**
596
     * @return \Illuminate\Http\JsonResponse
597
     */
598
    public function bulkRestore()
599
    {
600
        if ($this->repository->bulkRestore(explode(',', $this->request->get('ids')))) {
601
            $this->fireEvent();
602
            return $this->respondWithSuccess($this->modelTitle . ' items restored!');
603
        }
604
605
        return $this->respondWithError($this->modelTitle . ' items were not restored. Something wrong happened!');
606
    }
607
608
    /**
609
     * @return \Illuminate\Http\JsonResponse
610
     */
611
    public function feature()
612
    {
613
        if (($id = $this->request->get('id'))) {
614
            $featuredField = $this->request->get('featureField') ?? $this->featureField;
615
            $featured = !$this->request->get('active');
616
617
            if ($this->repository->isUniqueFeature()) {
618
                if ($featured) {
619
                    $this->repository->updateBasic(null, [$featuredField => false]);
620
                    $this->repository->updateBasic($id, [$featuredField => $featured]);
621
                }
622
            } else {
623
                $this->repository->updateBasic($id, [$featuredField => $featured]);
624
            }
625
626
            activity()->performedOn(
627
                $this->repository->getById($id)
628
            )->log(
629
                ($this->request->get('active') ? 'un' : '') . 'featured'
630
            );
631
632
            $this->fireEvent();
633
            return $this->respondWithSuccess($this->modelTitle . ' ' . ($this->request->get('active') ? 'un' : '') . 'featured!');
634
        }
635
636
        return $this->respondWithError($this->modelTitle . ' was not featured. Something wrong happened!');
637
    }
638
639
    /**
640
     * @return \Illuminate\Http\JsonResponse
641
     */
642
    public function bulkFeature()
643
    {
644
        if (($ids = explode(',', $this->request->get('ids')))) {
645
            $featuredField = $this->request->get('featureField') ?? $this->featureField;
646
            $featured = $this->request->get('feature') ?? true;
647
            // we don't need to check if unique feature since bulk operation shouldn't be allowed in this case
648
            $this->repository->updateBasic($ids, [$featuredField => $featured]);
649
            $this->fireEvent();
650
            return $this->respondWithSuccess($this->modelTitle . ' items ' . ($this->request->get('feature') ? '' : 'un') . 'featured!');
651
        }
652
653
        return $this->respondWithError($this->modelTitle . ' items were not featured. Something wrong happened!');
654
    }
655
656
    /**
657
     * @return \Illuminate\Http\JsonResponse
658
     */
659
    public function reorder()
660
    {
661
        if (($values = $this->request->get('ids')) && !empty($values)) {
662
            $this->repository->setNewOrder($values);
663
            $this->fireEvent();
664
            return $this->respondWithSuccess($this->modelTitle . ' order changed!');
665
        }
666
667
        return $this->respondWithError($this->modelTitle . ' order was not changed. Something wrong happened!');
668
    }
669
670
    /**
671
     * @return \Illuminate\Http\JsonResponse
672
     */
673
    public function tags()
674
    {
675
        $query = $this->request->input('q');
676
        $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

676
        /** @scrutinizer ignore-call */ 
677
        $tags = $this->repository->getTags($query);
Loading history...
677
678
        return Response::json(['items' => $tags->map(function ($tag) {
679
            return $tag->name;
680
        })], 200);
681
    }
682
683
    /**
684
     * @param array $prependScope
685
     * @return array
686
     */
687
    protected function getIndexData($prependScope = [])
688
    {
689
        $scopes = $this->filterScope($prependScope);
690
        $items = $this->getIndexItems($scopes);
691
692
        $data = [
693
            'tableData' => $this->getIndexTableData($items),
694
            'tableColumns' => $this->getIndexTableColumns($items),
695
            'tableMainFilters' => $this->getIndexTableMainFilters($items),
696
            'filters' => json_decode($this->request->get('filter'), true) ?? [],
697
            'hiddenFilters' => array_keys(Arr::except($this->filters, array_keys($this->defaultFilters))),
698
            'filterLinks' => $this->filterLinks ?? [],
699
            'maxPage' => method_exists($items, 'lastPage') ? $items->lastPage() : 1,
700
            'defaultMaxPage' => method_exists($items, 'total') ? ceil($items->total() / $this->perPage) : 1,
701
            'offset' => method_exists($items, 'perPage') ? $items->perPage() : count($items),
702
            'defaultOffset' => $this->perPage,
703
        ] + $this->getIndexUrls($this->moduleName, $this->routePrefix);
704
705
        $baseUrl = $this->getPermalinkBaseUrl();
706
707
        $options = [
708
            'moduleName' => $this->moduleName,
709
            'reorder' => $this->getIndexOption('reorder'),
710
            'create' => $this->getIndexOption('create'),
711
            'duplicate' => $this->getIndexOption('duplicate'),
712
            'translate' => $this->moduleHas('translations'),
713
            'permalink' => $this->getIndexOption('permalink'),
714
            'bulkEdit' => $this->getIndexOption('bulkEdit'),
715
            'titleFormKey' => $this->titleFormKey ?? $this->titleColumnKey,
716
            'baseUrl' => $baseUrl,
717
            'permalinkPrefix' => $this->getPermalinkPrefix($baseUrl),
718
        ];
719
720
        return array_replace_recursive($data + $options, $this->indexData($this->request));
721
    }
722
723
    /**
724
     * @param Request $request
725
     * @return array
726
     */
727
    protected function indexData($request)
728
    {
729
        return [];
730
    }
731
732
    /**
733
     * @param array $scopes
734
     * @param bool $forcePagination
735
     * @return \Illuminate\Database\Eloquent\Collection
736
     */
737
    protected function getIndexItems($scopes = [], $forcePagination = false)
738
    {
739
        return $this->transformIndexItems($this->repository->get(
740
            $this->indexWith,
741
            $scopes,
742
            $this->orderScope(),
743
            $this->request->get('offset') ?? $this->perPage ?? 50,
744
            $forcePagination
745
        ));
746
    }
747
748
    /**
749
     * @param \Illuminate\Database\Eloquent\Collection $items
750
     * @return \Illuminate\Database\Eloquent\Collection
751
     */
752
    protected function transformIndexItems($items)
753
    {
754
        return $items;
755
    }
756
757
    /**
758
     * @param \Illuminate\Database\Eloquent\Collection $items
759
     * @return array
760
     */
761
    protected function getIndexTableData($items)
762
    {
763
        $translated = $this->moduleHas('translations');
764
        return $items->map(function ($item) use ($translated) {
765
            $columnsData = Collection::make($this->indexColumns)->mapWithKeys(function ($column) use ($item) {
766
                return $this->getItemColumnData($item, $column);
767
            })->toArray();
768
769
            $name = $columnsData[$this->titleColumnKey];
770
771
            if (empty($name)) {
772
                if ($this->moduleHas('translations')) {
773
                    $fallBackTranslation = $item->translations()->where('active', true)->first();
774
775
                    if (isset($fallBackTranslation->{$this->titleColumnKey})) {
776
                        $name = $fallBackTranslation->{$this->titleColumnKey};
777
                    }
778
                }
779
780
                $name = $name ?? ('Missing ' . $this->titleColumnKey);
781
            }
782
783
            unset($columnsData[$this->titleColumnKey]);
784
785
            $itemIsTrashed = method_exists($item, 'trashed') && $item->trashed();
786
            $itemCanDelete = $this->getIndexOption('delete') && ($item->canDelete ?? true);
787
            $canEdit = $this->getIndexOption('edit');
788
            $canDuplicate = $this->getIndexOption('duplicate');
789
790
            return array_replace([
791
                'id' => $item->id,
792
                'name' => $name,
793
                'publish_start_date' => $item->publish_start_date,
794
                'publish_end_date' => $item->publish_end_date,
795
                'edit' => $canEdit ? $this->getModuleRoute($item->id, 'edit') : null,
796
                'duplicate' => $canDuplicate ? $this->getModuleRoute($item->id, 'duplicate') : null,
797
                'delete' => $itemCanDelete ? $this->getModuleRoute($item->id, 'destroy') : null,
798
            ] + ($this->getIndexOption('editInModal') ? [
799
                'editInModal' => $this->getModuleRoute($item->id, 'edit'),
800
                'updateUrl' => $this->getModuleRoute($item->id, 'update'),
801
            ] : []) + ($this->getIndexOption('publish') && ($item->canPublish ?? true) ? [
802
                'published' => $item->published,
803
            ] : []) + ($this->getIndexOption('feature') && ($item->canFeature ?? true) ? [
804
                'featured' => $item->{$this->featureField},
805
            ] : []) + (($this->getIndexOption('restore') && $itemIsTrashed) ? [
806
                'deleted' => true,
807
            ] : []) + ($translated ? [
808
                'languages' => $item->getActiveLanguages(),
809
            ] : []) + $columnsData, $this->indexItemData($item));
810
        })->toArray();
811
    }
812
813
    /**
814
     * @param \A17\Twill\Models\Model $item
815
     * @return array
816
     */
817
    protected function indexItemData($item)
818
    {
819
        return [];
820
    }
821
822
    /**
823
     * @param \A17\Twill\Models\Model $item
824
     * @param array $column
825
     * @return array
826
     */
827
    protected function getItemColumnData($item, $column)
828
    {
829
        if (isset($column['thumb']) && $column['thumb']) {
830
            if (isset($column['present']) && $column['present']) {
831
                return [
832
                    'thumbnail' => $item->presentAdmin()->{$column['presenter']},
833
                ];
834
            } else {
835
                $variant = isset($column['variant']);
836
                $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...
837
                $crop = $variant ? $column['variant']['crop'] : head(array_keys(head($item->mediasParams)));
838
                $params = $variant && isset($column['variant']['params'])
839
                ? $column['variant']['params']
840
                : ['w' => 80, 'h' => 80, 'fit' => 'crop'];
841
842
                return [
843
                    'thumbnail' => $item->cmsImage($role, $crop, $params),
844
                ];
845
            }
846
        }
847
848
        if (isset($column['nested']) && $column['nested']) {
849
            $field = $column['nested'];
850
            $nestedCount = $item->{$column['nested']}->count();
851
            $value = '<a href="';
852
            $value .= moduleRoute("$this->moduleName.$field", $this->routePrefix, 'index', [$item->id]);
853
            $value .= '">' . $nestedCount . " " . (strtolower($nestedCount > 1
854
                ? Str::plural($column['title'])
855
                : Str::singular($column['title']))) . '</a>';
856
        } else {
857
            $field = $column['field'];
858
            $value = $item->$field;
859
        }
860
861
        if (isset($column['relationship'])) {
862
            $field = $column['relationship'] . ucfirst($column['field']);
863
            $value = Arr::get($item, "{$column['relationship']}.{$column['field']}");
864
        } elseif (isset($column['present']) && $column['present']) {
865
            $value = $item->presentAdmin()->{$column['field']};
866
        }
867
868
        return [
869
            "$field" => $value,
870
        ];
871
    }
872
873
    /**
874
     * @param \Illuminate\Database\Eloquent\Collection $items
875
     * @return array
876
     */
877
    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

877
    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...
878
    {
879
        $tableColumns = [];
880
        $visibleColumns = $this->request->get('columns') ?? false;
881
882
        if (isset(Arr::first($this->indexColumns)['thumb'])
883
            && Arr::first($this->indexColumns)['thumb']
884
        ) {
885
            array_push($tableColumns, [
886
                'name' => 'thumbnail',
887
                'label' => 'Thumbnail',
888
                'visible' => $visibleColumns ? in_array('thumbnail', $visibleColumns) : true,
889
                'optional' => true,
890
                'sortable' => false,
891
            ]);
892
            array_shift($this->indexColumns);
893
        }
894
895
        if ($this->getIndexOption('feature')) {
896
            array_push($tableColumns, [
897
                'name' => 'featured',
898
                'label' => 'Featured',
899
                'visible' => true,
900
                'optional' => false,
901
                'sortable' => false,
902
            ]);
903
        }
904
905
        if ($this->getIndexOption('publish')) {
906
            array_push($tableColumns, [
907
                'name' => 'published',
908
                'label' => 'Published',
909
                'visible' => true,
910
                'optional' => false,
911
                'sortable' => false,
912
            ]);
913
        }
914
915
        array_push($tableColumns, [
916
            'name' => 'name',
917
            'label' => $this->indexColumns[$this->titleColumnKey]['title'] ?? 'Name',
918
            'visible' => true,
919
            'optional' => false,
920
            'sortable' => $this->getIndexOption('reorder') ? false : ($this->indexColumns[$this->titleColumnKey]['sort'] ?? false),
921
        ]);
922
923
        unset($this->indexColumns[$this->titleColumnKey]);
924
925
        foreach ($this->indexColumns as $column) {
926
            $columnName = isset($column['relationship'])
927
            ? $column['relationship'] . ucfirst($column['field'])
928
            : (isset($column['nested']) ? $column['nested'] : $column['field']);
929
930
            array_push($tableColumns, [
931
                'name' => $columnName,
932
                'label' => $column['title'],
933
                'visible' => $visibleColumns ? in_array($columnName, $visibleColumns) : ($column['visible'] ?? true),
934
                'optional' => $column['optional'] ?? true,
935
                'sortable' => $this->getIndexOption('reorder') ? false : ($column['sort'] ?? false),
936
                'html' => $column['html'] ?? false,
937
            ]);
938
        }
939
940
        if ($this->moduleHas('translations')) {
941
            array_push($tableColumns, [
942
                'name' => 'languages',
943
                'label' => 'Languages',
944
                'visible' => $visibleColumns ? in_array('languages', $visibleColumns) : true,
945
                'optional' => true,
946
                'sortable' => false,
947
            ]);
948
        }
949
950
        return $tableColumns;
951
    }
952
953
    /**
954
     * @param \Illuminate\Database\Eloquent\Collection $items
955
     * @param array $scopes
956
     * @return array
957
     */
958
    protected function getIndexTableMainFilters($items, $scopes = [])
959
    {
960
        $statusFilters = [];
961
962
        $scope = ($this->submodule ? [
963
            $this->getParentModuleForeignKey() => $this->submoduleParentId,
964
        ] : []) + $scopes;
965
966
        array_push($statusFilters, [
967
            'name' => 'All items',
968
            'slug' => 'all',
969
            'number' => $this->repository->getCountByStatusSlug('all', $scope),
970
        ]);
971
972
        if ($this->moduleHas('revisions') && $this->getIndexOption('create')) {
973
            array_push($statusFilters, [
974
                'name' => 'Mine',
975
                'slug' => 'mine',
976
                'number' => $this->repository->getCountByStatusSlug('mine', $scope),
977
            ]);
978
        }
979
980
        if ($this->getIndexOption('publish')) {
981
            array_push($statusFilters, [
982
                'name' => 'Published',
983
                'slug' => 'published',
984
                'number' => $this->repository->getCountByStatusSlug('published', $scope),
985
            ], [
986
                'name' => 'Draft',
987
                'slug' => 'draft',
988
                'number' => $this->repository->getCountByStatusSlug('draft', $scope),
989
            ]);
990
        }
991
992
        if ($this->getIndexOption('restore')) {
993
            array_push($statusFilters, [
994
                'name' => 'Trash',
995
                'slug' => 'trash',
996
                'number' => $this->repository->getCountByStatusSlug('trash', $scope),
997
            ]);
998
        }
999
1000
        return $statusFilters;
1001
    }
1002
1003
    /**
1004
     * @param string $moduleName
1005
     * @param string $routePrefix
1006
     * @return array
1007
     */
1008
    protected function getIndexUrls($moduleName, $routePrefix)
1009
    {
1010
        return Collection::make([
1011
            'store',
1012
            'publish',
1013
            'bulkPublish',
1014
            'restore',
1015
            'bulkRestore',
1016
            'reorder',
1017
            'feature',
1018
            'bulkFeature',
1019
            'bulkDelete',
1020
        ])->mapWithKeys(function ($endpoint) use ($moduleName, $routePrefix) {
0 ignored issues
show
Unused Code introduced by
The import $moduleName is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
Unused Code introduced by
The import $routePrefix is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
1021
            return [
1022
                $endpoint . 'Url' => $this->getIndexOption($endpoint) ? moduleRoute(
1023
                    $this->moduleName, $this->routePrefix, $endpoint,
1024
                    $this->submodule ? [$this->submoduleParentId] : []
1025
                ) : null,
1026
            ];
1027
        })->toArray();
1028
    }
1029
1030
    /**
1031
     * @param string $option
1032
     * @return bool
1033
     */
1034
    protected function getIndexOption($option)
1035
    {
1036
        return once(function () use ($option) {
1037
            $customOptionNamesMapping = [
1038
                'store' => 'create',
1039
            ];
1040
1041
            $option = array_key_exists($option, $customOptionNamesMapping) ? $customOptionNamesMapping[$option] : $option;
1042
1043
            $authorizableOptions = [
1044
                'create' => 'edit',
1045
                'edit' => 'edit',
1046
                'publish' => 'publish',
1047
                'feature' => 'feature',
1048
                'reorder' => 'reorder',
1049
                'delete' => 'delete',
1050
                'duplicate' => 'duplicate',
1051
                'restore' => 'delete',
1052
                'bulkPublish' => 'publish',
1053
                'bulkRestore' => 'delete',
1054
                'bulkFeature' => 'feature',
1055
                'bulkDelete' => 'delete',
1056
                'bulkEdit' => 'edit',
1057
                'editInModal' => 'edit',
1058
            ];
1059
1060
            $authorized = array_key_exists($option, $authorizableOptions) ? Auth::guard('twill_users')->user()->can($authorizableOptions[$option]) : true;
1061
            return ($this->indexOptions[$option] ?? $this->defaultIndexOptions[$option] ?? false) && $authorized;
1062
        });
1063
    }
1064
1065
    /**
1066
     * @param array $prependScope
1067
     * @return array
1068
     */
1069
    protected function getBrowserData($prependScope = [])
1070
    {
1071
        if ($this->request->has('except')) {
1072
            $prependScope['exceptIds'] = $this->request->get('except');
1073
        }
1074
1075
        $scopes = $this->filterScope($prependScope);
1076
        $items = $this->getBrowserItems($scopes);
1077
        $data = $this->getBrowserTableData($items);
1078
1079
        return array_replace_recursive(['data' => $data], $this->indexData($this->request));
1080
    }
1081
1082
    /**
1083
     * @param \Illuminate\Database\Eloquent\Collection $items
1084
     * @return array
1085
     */
1086
    protected function getBrowserTableData($items)
1087
    {
1088
        $withImage = $this->moduleHas('medias');
1089
1090
        return $items->map(function ($item) use ($withImage) {
1091
            $columnsData = Collection::make($this->browserColumns)->mapWithKeys(function ($column) use ($item, $withImage) {
0 ignored issues
show
Unused Code introduced by
The import $withImage is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
1092
                return $this->getItemColumnData($item, $column);
1093
            })->toArray();
1094
1095
            $name = $columnsData[$this->titleColumnKey];
1096
            unset($columnsData[$this->titleColumnKey]);
1097
1098
            return [
1099
                'id' => $item->id,
1100
                'name' => $name,
1101
                'edit' => moduleRoute($this->moduleName, $this->routePrefix, 'edit', $item->id),
1102
                '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

1102
                'endpointType' => $this->repository->/** @scrutinizer ignore-call */ getMorphClass(),
Loading history...
1103
            ] + $columnsData + ($withImage && !array_key_exists('thumbnail', $columnsData) ? [
1104
                'thumbnail' => $item->defaultCmsImage(['w' => 100, 'h' => 100]),
1105
            ] : []);
1106
        })->toArray();
1107
    }
1108
1109
    /**
1110
     * @param array $scopes
1111
     * @return \Illuminate\Database\Eloquent\Collection
1112
     */
1113
    protected function getBrowserItems($scopes = [])
1114
    {
1115
        return $this->getIndexItems($scopes, true);
1116
    }
1117
1118
    /**
1119
     * @param array $prepend
1120
     * @return array
1121
     */
1122
    protected function filterScope($prepend = [])
1123
    {
1124
        $scope = [];
1125
1126
        $requestFilters = $this->getRequestFilters();
1127
1128
        $this->filters = array_merge($this->filters, $this->defaultFilters);
1129
1130
        if (array_key_exists('status', $requestFilters)) {
1131
            switch ($requestFilters['status']) {
1132
                case 'published':
1133
                    $scope['published'] = true;
1134
                    break;
1135
                case 'draft':
1136
                    $scope['draft'] = true;
1137
                    break;
1138
                case 'trash':
1139
                    $scope['onlyTrashed'] = true;
1140
                    break;
1141
                case 'mine':
1142
                    $scope['mine'] = true;
1143
                    break;
1144
            }
1145
1146
            unset($requestFilters['status']);
1147
        }
1148
1149
        foreach ($this->filters as $key => $field) {
1150
            if (array_key_exists($key, $requestFilters)) {
1151
                $value = $requestFilters[$key];
1152
                if ($value == 0 || !empty($value)) {
1153
                    // add some syntaxic sugar to scope the same filter on multiple columns
1154
                    $fieldSplitted = explode('|', $field);
1155
                    if (count($fieldSplitted) > 1) {
1156
                        $requestValue = $requestFilters[$key];
1157
                        Collection::make($fieldSplitted)->each(function ($scopeKey) use (&$scope, $requestValue) {
1158
                            $scope[$scopeKey] = $requestValue;
1159
                        });
1160
                    } else {
1161
                        $scope[$field] = $requestFilters[$key];
1162
                    }
1163
                }
1164
            }
1165
        }
1166
1167
        return $prepend + $scope;
1168
    }
1169
1170
    /**
1171
     * @return array
1172
     */
1173
    protected function getRequestFilters()
1174
    {
1175
        if ($this->request->has('search')) {
1176
            return ['search' => $this->request->get('search')];
1177
        }
1178
1179
        return json_decode($this->request->get('filter'), true) ?? [];
1180
    }
1181
1182
    /**
1183
     * @return array
1184
     */
1185
    protected function orderScope()
1186
    {
1187
        $orders = [];
1188
        if ($this->request->has('sortKey') && $this->request->has('sortDir')) {
1189
            if (($key = $this->request->get('sortKey')) == 'name') {
1190
                $sortKey = $this->titleColumnKey;
1191
            } elseif (!empty($key)) {
1192
                $sortKey = $key;
1193
            }
1194
1195
            if (isset($sortKey)) {
1196
                $orders[$this->indexColumns[$sortKey]['sortKey'] ?? $sortKey] = $this->request->get('sortDir');
1197
            }
1198
        }
1199
1200
        // don't apply default orders if reorder is enabled
1201
        $reorder = $this->getIndexOption('reorder');
1202
        $defaultOrders = ($reorder ? [] : ($this->defaultOrders ?? []));
1203
1204
        return $orders + $defaultOrders;
1205
    }
1206
1207
    /**
1208
     * @param int $id
1209
     * @param \A17\Twill\Models\Model|null $item
1210
     * @return array
1211
     */
1212
    protected function form($id, $item = null)
1213
    {
1214
        $item = $item ?? $this->repository->getById($id, $this->formWith, $this->formWithCount);
1215
1216
        $fullRoutePrefix = 'admin.' . ($this->routePrefix ? $this->routePrefix . '.' : '') . $this->moduleName . '.';
1217
        $previewRouteName = $fullRoutePrefix . 'preview';
1218
        $restoreRouteName = $fullRoutePrefix . 'restoreRevision';
1219
1220
        $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...
1221
1222
        $data = [
1223
            'item' => $item,
1224
            'moduleName' => $this->moduleName,
1225
            'routePrefix' => $this->routePrefix,
1226
            'titleFormKey' => $this->titleFormKey ?? $this->titleColumnKey,
1227
            '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...
1228
            'translate' => $this->moduleHas('translations'),
1229
            'permalink' => $this->getIndexOption('permalink'),
1230
            'form_fields' => $this->repository->getFormFields($item),
1231
            'baseUrl' => $baseUrl,
1232
            'permalinkPrefix' => $this->getPermalinkPrefix($baseUrl),
1233
            'saveUrl' => $this->getModuleRoute($item->id, 'update'),
1234
            'editor' => $this->moduleHas('revisions') && $this->moduleHas('blocks') && !$this->disableEditor,
1235
            'blockPreviewUrl' => Route::has('admin.blocks.preview')? URL::route('admin.blocks.preview') : '#',
1236
            'revisions' => $this->moduleHas('revisions') ? $item->revisionsArray() : null,
1237
        ] + (Route::has($previewRouteName) ? [
1238
            '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

1238
            'previewUrl' => moduleRoute($this->moduleName, $this->routePrefix, 'preview', /** @scrutinizer ignore-type */ $item->id),
Loading history...
1239
        ] : [])
1240
             + (Route::has($restoreRouteName) ? [
1241
            'restoreUrl' => moduleRoute($this->moduleName, $this->routePrefix, 'restoreRevision', $item->id),
1242
        ] : []);
1243
1244
        return array_replace_recursive($data, $this->formData($this->request));
1245
    }
1246
1247
    /**
1248
     * @param int $id
1249
     * @return array
1250
     */
1251
    protected function modalFormData($id)
1252
    {
1253
        $item = $this->repository->getById($id, $this->formWith, $this->formWithCount);
1254
        $fields = $this->repository->getFormFields($item);
1255
        $data = [];
1256
1257
        if ($this->moduleHas('translations') && isset($fields['translations'])) {
1258
            foreach ($fields['translations'] as $fieldName => $fieldValue) {
1259
                $data['fields'][] = [
1260
                    'name' => $fieldName,
1261
                    'value' => $fieldValue,
1262
                ];
1263
            }
1264
1265
            $data['languages'] = $item->getActiveLanguages();
1266
1267
            unset($fields['translations']);
1268
        }
1269
1270
        foreach ($fields as $fieldName => $fieldValue) {
1271
            $data['fields'][] = [
1272
                'name' => $fieldName,
1273
                'value' => $fieldValue,
1274
            ];
1275
        }
1276
1277
        return array_replace_recursive($data, $this->formData($this->request));
1278
    }
1279
1280
    /**
1281
     * @param Request $request
1282
     * @return array
1283
     */
1284
    protected function formData($request)
1285
    {
1286
        return [];
1287
    }
1288
1289
    /**
1290
     * @param Request $item
1291
     * @return array
1292
     */
1293
    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

1293
    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...
1294
    {
1295
        return [];
1296
    }
1297
1298
    /**
1299
     * @return \A17\Twill\Http\Requests\Admin\Request
1300
     */
1301
    protected function validateFormRequest()
1302
    {
1303
        $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

1303
        $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...
1304
            return Auth::guard('twill_users')->user()->cannot($permission);
1305
        })->keys();
1306
1307
        $unauthorizedFields->each(function ($field) {
1308
            $this->request->offsetUnset($field);
1309
        });
1310
1311
        return App::make("$this->namespace\Http\Requests\Admin\\" . $this->modelName . "Request");
1312
    }
1313
1314
    /**
1315
     * @return string
1316
     */
1317
    protected function getNamespace()
1318
    {
1319
        return $this->namespace ?? Config::get('twill.namespace');
1320
    }
1321
1322
    /**
1323
     * @return string
1324
     */
1325
    protected function getRoutePrefix()
1326
    {
1327
        if ($this->request->route() != null) {
1328
            $routePrefix = ltrim(str_replace(Config::get('twill.admin_app_path'), '', $this->request->route()->getPrefix()), "/");
1329
            return str_replace("/", ".", $routePrefix);
1330
        }
1331
1332
        return '';
1333
    }
1334
1335
    /**
1336
     * @return string
1337
     */
1338
    protected function getModelName()
1339
    {
1340
        return $this->modelName ?? ucfirst(Str::singular($this->moduleName));
1341
    }
1342
1343
    /**
1344
     * @return \A17\Twill\Repositories\ModuleRepository
1345
     */
1346
    protected function getRepository()
1347
    {
1348
        return App::make("$this->namespace\Repositories\\" . $this->modelName . "Repository");
1349
    }
1350
1351
    /**
1352
     * @return string
1353
     */
1354
    protected function getViewPrefix()
1355
    {
1356
        return "admin.$this->moduleName";
1357
    }
1358
1359
    /**
1360
     * @return string
1361
     */
1362
    protected function getModelTitle()
1363
    {
1364
        return camelCaseToWords($this->modelName);
1365
    }
1366
1367
    /**
1368
     * @return string
1369
     */
1370
    protected function getParentModuleForeignKey()
1371
    {
1372
        return Str::singular(explode('.', $this->moduleName)[0]) . '_id';
1373
    }
1374
1375
    /**
1376
     * @return string
1377
     */
1378
    protected function getPermalinkBaseUrl()
1379
    {
1380
        return $this->request->getScheme() . '://' . Config::get('app.url') . '/'
1381
            . ($this->moduleHas('translations') ? '{language}/' : '')
1382
            . ($this->moduleHas('revisions') ? '{preview}/' : '')
1383
            . ($this->permalinkBase ?? $this->moduleName)
0 ignored issues
show
Bug Best Practice introduced by
The property permalinkBase does not exist on A17\Twill\Http\Controllers\Admin\ModuleController. Did you maybe forget to declare it?
Loading history...
1384
            . (isset($this->permalinkBase) && empty($this->permalinkBase) ? '' : '/');
1385
    }
1386
1387
    /**
1388
     * @param string $baseUrl
1389
     * @return string
1390
     */
1391
    protected function getPermalinkPrefix($baseUrl)
1392
    {
1393
        return rtrim(str_replace(['http://', 'https://', '{preview}/', '{language}/'], '', $baseUrl), "/") . '/';
1394
    }
1395
1396
    /**
1397
     * @param int $id
1398
     * @param string $action
1399
     * @return string
1400
     */
1401
    protected function getModuleRoute($id, $action)
1402
    {
1403
        return moduleRoute(
1404
            $this->moduleName,
1405
            $this->routePrefix,
1406
            $action,
1407
            array_merge($this->submodule ? [$this->submoduleParentId] : [], [$id])
1408
        );
1409
    }
1410
1411
    /**
1412
     * @param string $behavior
1413
     * @return bool
1414
     */
1415
    protected function moduleHas($behavior)
1416
    {
1417
        return classHasTrait($this->repository, 'A17\Twill\Repositories\Behaviors\Handle' . ucfirst($behavior));
1418
    }
1419
1420
    /**
1421
     * @param string|null $back_link
1422
     * @param array $params
1423
     * @return void
1424
     */
1425
    protected function setBackLink($back_link = null, $params = [])
1426
    {
1427
        if (!isset($back_link)) {
1428
            if (($back_link = Session::get($this->getBackLinkSessionKey())) == null) {
1429
                $back_link = $this->request->headers->get('referer') ?? moduleRoute(
1430
                    $this->moduleName,
1431
                    $this->routePrefix,
1432
                    'index',
1433
                    $params
1434
                );
1435
            }
1436
        }
1437
1438
        if (!Session::get($this->moduleName . '_retain')) {
1439
            Session::put($this->getBackLinkSessionKey(), $back_link);
1440
        } else {
1441
            Session::put($this->moduleName . '_retain', false);
1442
        }
1443
    }
1444
1445
    /**
1446
     * @param string|null $fallback
1447
     * @param array $params
1448
     * @return string
1449
     */
1450
    protected function getBackLink($fallback = null, $params = [])
1451
    {
1452
        $back_link = Session::get($this->getBackLinkSessionKey(), $fallback);
1453
        return $back_link ?? moduleRoute($this->moduleName, $this->routePrefix, 'index', $params);
1454
    }
1455
1456
    /**
1457
     * @return string
1458
     */
1459
    protected function getBackLinkSessionKey()
1460
    {
1461
        return $this->moduleName . ($this->submodule ? $this->submoduleParentId ?? '' : '') . '_back_link';
1462
    }
1463
1464
    /**
1465
     * @param int $id
1466
     * @param array $params
1467
     * @return \Illuminate\Http\RedirectResponse
1468
     */
1469
    protected function redirectToForm($id, $params = [])
1470
    {
1471
        Session::put($this->moduleName . '_retain', true);
1472
1473
        return Redirect::to(moduleRoute(
1474
            $this->moduleName,
1475
            $this->routePrefix,
1476
            'edit',
1477
            array_filter($params) + ['id' => $id]
1478
        ));
1479
    }
1480
1481
    /**
1482
     * @param string $message
1483
     * @return \Illuminate\Http\JsonResponse
1484
     */
1485
    protected function respondWithSuccess($message)
1486
    {
1487
        return $this->respondWithJson($message, FlashLevel::SUCCESS);
1488
    }
1489
1490
    /**
1491
     * @param string $redirectUrl
1492
     * @return \Illuminate\Http\JsonResponse
1493
     */
1494
    protected function respondWithRedirect($redirectUrl)
1495
    {
1496
        return Response::json([
1497
            'redirect' => $redirectUrl,
1498
        ]);
1499
    }
1500
1501
    /**
1502
     * @param string $message
1503
     * @return \Illuminate\Http\JsonResponse
1504
     */
1505
    protected function respondWithError($message)
1506
    {
1507
        return $this->respondWithJson($message, FlashLevel::ERROR);
1508
    }
1509
1510
    /**
1511
     * @param string $message
1512
     * @param mixed $variant
1513
     * @return \Illuminate\Http\JsonResponse
1514
     */
1515
    protected function respondWithJson($message, $variant)
1516
    {
1517
        return Response::json([
1518
            'message' => $message,
1519
            'variant' => $variant,
1520
        ]);
1521
    }
1522
1523
    /**
1524
     * @param array $input
1525
     * @return void
1526
     */
1527
    protected function fireEvent($input = [])
1528
    {
1529
        fireCmsEvent('cms-module.saved', $input);
1530
    }
1531
}
1532