Passed
Push — master ( e1e679...09e224 )
by Quentin
10:29
created

ModuleController::titleIsTranslatable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
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
     * Default orders for the index view.
134
     *
135
     * @var array
136
     */
137
    protected $defaultOrders = [
138
        'created_at' => 'desc',
139
    ];
140
141
    /**
142
     * @var int
143
     */
144
    protected $perPage = 20;
145
146
    /**
147
     * Name of the index column to use as name column.
148
     *
149
     * @var string
150
     */
151
    protected $titleColumnKey = 'title';
152
153
    /**
154
     * Attribute to use as title in forms.
155
     *
156
     * @var string
157
     */
158
    protected $titleFormKey;
159
160
    /**
161
     * Feature field name if the controller is using the feature route (defaults to "featured").
162
     *
163
     * @var string
164
     */
165
    protected $featureField = 'featured';
166
167
    /**
168
     * Indicates if this module is edited through a parent module.
169
     *
170
     * @var bool
171
     */
172
    protected $submodule = false;
173
174
    /**
175
     * @var int|null
176
     */
177
    protected $submoduleParentId = null;
178
179
    /**
180
     * Can be used in child classes to disable the content editor (full screen block editor).
181
     *
182
     * @var bool
183
     */
184
    protected $disableEditor = false;
185
186
    /**
187
     * @var array
188
     */
189
    protected $indexOptions;
190
191
    /**
192
     * @var array
193
     */
194
    protected $indexColumns;
195
196
    /**
197
     * @var array
198
     */
199
    protected $browserColumns;
200
201
    /**
202
     * @var string
203
     */
204
    protected $permalinkBase;
205
206
    /**
207
     * @var array
208
     */
209
    protected $defaultFilters;
210
211
    /**
212
     * @var string
213
     */
214
    protected $viewPrefix;
215
216
    /**
217
     * @var string
218
     */
219
    protected $previewView;
220
221
    /**
222
     * List of permissions keyed by a request field. Can be used to prevent unauthorized field updates.
223
     *
224
     * @var array
225
     */
226
    protected $fieldsPermissions = [];
227
228 40
    public function __construct(Application $app, Request $request)
229
    {
230 40
        parent::__construct();
231 40
        $this->app = $app;
232 40
        $this->request = $request;
233
234 40
        $this->setMiddlewarePermission();
235
236 40
        $this->modelName = $this->getModelName();
237 40
        $this->routePrefix = $this->getRoutePrefix();
238 40
        $this->namespace = $this->getNamespace();
239 40
        $this->repository = $this->getRepository();
240 40
        $this->viewPrefix = $this->getViewPrefix();
241 40
        $this->modelTitle = $this->getModelTitle();
242
243
        /*
244
         * Default filters for the index view
245
         * By default, the search field will run a like query on the title field
246
         */
247 40
        if (!isset($this->defaultFilters)) {
248 26
            $this->defaultFilters = [
249 26
                'search' => ($this->moduleHas('translations') ? '' : '%') . $this->titleColumnKey,
250
            ];
251
        }
252
253
        /*
254
         * Available columns of the index view
255
         */
256 40
        if (!isset($this->indexColumns)) {
257 13
            $this->indexColumns = [
258 13
                $this->titleColumnKey => [
259 13
                    'title' => ucfirst($this->titleColumnKey),
260 13
                    'field' => $this->titleColumnKey,
261
                    'sort' => true,
262
                ],
263
            ];
264
        }
265
266
        /*
267
         * Available columns of the browser view
268
         */
269 40
        if (!isset($this->browserColumns)) {
270 40
            $this->browserColumns = [
271 40
                $this->titleColumnKey => [
272 40
                    'title' => ucfirst($this->titleColumnKey),
273 40
                    'field' => $this->titleColumnKey,
274
                ],
275
            ];
276
        }
277 40
    }
278
279
    /**
280
     * @return void
281
     */
282 40
    protected function setMiddlewarePermission()
283
    {
284 40
        $this->middleware('can:list', ['only' => ['index', 'show']]);
285 40
        $this->middleware('can:edit', ['only' => ['store', 'edit', 'update']]);
286 40
        $this->middleware('can:publish', ['only' => ['publish', 'feature', 'bulkPublish', 'bulkFeature']]);
287 40
        $this->middleware('can:reorder', ['only' => ['reorder']]);
288 40
        $this->middleware('can:delete', ['only' => ['destroy', 'bulkDelete', 'restore', 'bulkRestore', 'forceDelete', 'bulkForceDelete', 'restoreRevision']]);
289 40
    }
290
291
    /**
292
     * @param int|null $parentModuleId
293
     * @return array|\Illuminate\View\View
294
     */
295 6
    public function index($parentModuleId = null)
296
    {
297 6
        $this->submodule = isset($parentModuleId);
298 6
        $this->submoduleParentId = $parentModuleId;
299
300 6
        $indexData = $this->getIndexData($this->submodule ? [
301
            $this->getParentModuleForeignKey() => $this->submoduleParentId,
302 6
        ] : []);
303
304 6
        if ($this->request->ajax()) {
305 3
            return $indexData + ['replaceUrl' => true];
306
        }
307
308 3
        if ($this->request->has('openCreate') && $this->request->get('openCreate')) {
309
            $indexData += ['openCreate' => true];
310
        }
311
312 3
        $view = Collection::make([
313 3
            "$this->viewPrefix.index",
314 3
            "twill::$this->moduleName.index",
315 3
            "twill::layouts.listing",
316
        ])->first(function ($view) {
317 3
            return View::exists($view);
318 3
        });
319
320 3
        return View::make($view, $indexData);
321
    }
322
323
    /**
324
     * @return \Illuminate\Http\JsonResponse
325
     */
326 2
    public function browser()
327
    {
328 2
        return Response::json($this->getBrowserData());
329
    }
330
331
    /**
332
     * @param int|null $parentModuleId
333
     * @return \Illuminate\Http\JsonResponse
334
     */
335 21
    public function store($parentModuleId = null)
336
    {
337 21
        $input = $this->validateFormRequest()->all();
338 21
        $optionalParent = $parentModuleId ? [$this->getParentModuleForeignKey() => $parentModuleId] : [];
339
340 21
        $item = $this->repository->create($input + $optionalParent);
341
342 21
        activity()->performedOn($item)->log('created');
343
344 21
        $this->fireEvent($input);
345
346 21
        Session::put($this->moduleName . '_retain', true);
347
348 21
        if ($this->getIndexOption('editInModal')) {
349 2
            return $this->respondWithSuccess('Content saved. All good!');
350
        }
351
352 19
        return $this->respondWithRedirect(moduleRoute(
353 19
            $this->moduleName,
354 19
            $this->routePrefix,
355 19
            'edit',
356 19
            array_filter([$parentModuleId]) + [Str::singular($this->moduleName) => $item->id]
357
        ));
358
    }
359
360
    /**
361
     * @param int|$id
362
     * @param int|null $submoduleId
363
     * @return \Illuminate\Http\RedirectResponse
364
     */
365 1
    public function show($id, $submoduleId = null)
366
    {
367 1
        if ($this->getIndexOption('editInModal')) {
368
            return Redirect::to(moduleRoute($this->moduleName, $this->routePrefix, 'index'));
369
        }
370
371 1
        return $this->redirectToForm($submoduleId ?? $id);
372
    }
373
374
    /**
375
     * @param int $id
376
     * @param int|null $submoduleId
377
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\View\View
378
     */
379 5
    public function edit($id, $submoduleId = null)
380
    {
381 5
        $this->submodule = isset($submoduleId);
382 5
        $this->submoduleParentId = $id;
383
384 5
        if ($this->getIndexOption('editInModal')) {
385 2
            return $this->request->ajax()
386 1
            ? Response::json($this->modalFormData($submoduleId ?? $id))
387 2
            : Redirect::to(moduleRoute($this->moduleName, $this->routePrefix, 'index'));
388
        }
389
390 3
        $this->setBackLink();
391
392 3
        $view = Collection::make([
393 3
            "$this->viewPrefix.form",
394 3
            "twill::$this->moduleName.form",
395 3
            "twill::layouts.form",
396
        ])->first(function ($view) {
397 3
            return View::exists($view);
398 3
        });
399
400 3
        return View::make($view, $this->form($submoduleId ?? $id));
401
    }
402
403
    /**
404
     * @param int $id
405
     * @param int|null $submoduleId
406
     * @return \Illuminate\Http\JsonResponse
407
     */
408 7
    public function update($id, $submoduleId = null)
409
    {
410 7
        $this->submodule = isset($submoduleId);
411 7
        $this->submoduleParentId = $id;
412
413 7
        $item = $this->repository->getById($submoduleId ?? $id);
414 7
        $input = $this->request->all();
415
416 7
        if (isset($input['cmsSaveType']) && $input['cmsSaveType'] === 'cancel') {
417
            return $this->respondWithRedirect(moduleRoute(
418
                $this->moduleName,
419
                $this->routePrefix,
420
                'edit',
421
                [Str::singular($this->moduleName) => $id]
422
            ));
423
        } else {
424 7
            $formRequest = $this->validateFormRequest();
425
426 7
            $this->repository->update($submoduleId ?? $id, $formRequest->all());
427
428 7
            activity()->performedOn($item)->log('updated');
429
430 7
            $this->fireEvent();
431
432 7
            if (isset($input['cmsSaveType'])) {
433 7
                if (Str::endsWith($input['cmsSaveType'], '-close')) {
434
                    return $this->respondWithRedirect($this->getBackLink());
435 7
                } elseif (Str::endsWith($input['cmsSaveType'], '-new')) {
436
                    return $this->respondWithRedirect(moduleRoute(
437
                        $this->moduleName,
438
                        $this->routePrefix,
439
                        'index',
440
                        ['openCreate' => true]
441
                    ));
442 7
                } elseif ($input['cmsSaveType'] === 'restore') {
443
                    Session::flash('status', "Revision restored.");
444
445
                    return $this->respondWithRedirect(moduleRoute(
446
                        $this->moduleName,
447
                        $this->routePrefix,
448
                        'edit',
449
                        [Str::singular($this->moduleName) => $id]
450
                    ));
451
                }
452
            }
453
454 7
            if ($this->moduleHas('revisions')) {
455 6
                return Response::json([
456 6
                    'message' => 'Content saved. All good!',
457
                    'variant' => FlashLevel::SUCCESS,
458 6
                    'revisions' => $item->revisionsArray(),
459
                ]);
460
            }
461
462 1
            return $this->respondWithSuccess('Content saved. All good!');
463
        }
464
    }
465
466
    /**
467
     * @param int $id
468
     * @return \Illuminate\View\View
469
     */
470 1
    public function preview($id)
471
    {
472 1
        if ($this->request->has('revisionId')) {
473
            $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

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

476
            /** @scrutinizer ignore-call */ 
477
            $item = $this->repository->preview($id, $formRequest->all());
Loading history...
477
        }
478
479 1
        if ($this->request->has('activeLanguage')) {
480
            App::setLocale($this->request->get('activeLanguage'));
481
        }
482
483 1
        $previewView = $this->previewView ?? (Config::get('twill.frontend.views_path', 'site') . '.' . Str::singular($this->moduleName));
484
485 1
        return View::exists($previewView) ? View::make($previewView, array_replace([
486 1
            'item' => $item,
487 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

487
        ], $this->previewData(/** @scrutinizer ignore-type */ $item))) : View::make('twill::errors.preview', [
Loading history...
488 1
            'moduleName' => Str::singular($this->moduleName),
489
        ]);
490
    }
491
492
    /**
493
     * @param int $id
494
     * @return \Illuminate\View\View
495
     */
496 2
    public function restoreRevision($id)
497
    {
498 2
        if ($this->request->has('revisionId')) {
499 1
            $item = $this->repository->previewForRevision($id, $this->request->get('revisionId'));
500 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...
501 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...
502
        } else {
503 1
            throw new NotFoundHttpException();
504
        }
505
506 1
        $this->setBackLink();
507
508 1
        $view = Collection::make([
509 1
            "$this->viewPrefix.form",
510 1
            "twill::$this->moduleName.form",
511 1
            "twill::layouts.form",
512
        ])->first(function ($view) {
513 1
            return View::exists($view);
514 1
        });
515
516 1
        $revision = $item->revisions()->where('id', $this->request->get('revisionId'))->first();
517 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

517
        /** @scrutinizer ignore-call */ 
518
        $date = $revision->created_at->toDayDateTimeString();
Loading history...
518
519 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...
520
521 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

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

729
        /** @scrutinizer ignore-call */ 
730
        $tags = $this->repository->getTags($query);
Loading history...
730
731
        return Response::json(['items' => $tags->map(function ($tag) {
732
            return $tag->name;
733 1
        })], 200);
734
    }
735
736
    /**
737
     * @param array $prependScope
738
     * @return array
739
     */
740 6
    protected function getIndexData($prependScope = [])
741
    {
742 6
        $scopes = $this->filterScope($prependScope);
743 6
        $items = $this->getIndexItems($scopes);
744
745
        $data = [
746 6
            'tableData' => $this->getIndexTableData($items),
747 6
            'tableColumns' => $this->getIndexTableColumns($items),
748 6
            'tableMainFilters' => $this->getIndexTableMainFilters($items),
749 6
            'filters' => json_decode($this->request->get('filter'), true) ?? [],
750 6
            'hiddenFilters' => array_keys(Arr::except($this->filters, array_keys($this->defaultFilters))),
751 6
            'filterLinks' => $this->filterLinks ?? [],
752 6
            'maxPage' => method_exists($items, 'lastPage') ? $items->lastPage() : 1,
753 6
            'defaultMaxPage' => method_exists($items, 'total') ? ceil($items->total() / $this->perPage) : 1,
754 6
            'offset' => method_exists($items, 'perPage') ? $items->perPage() : count($items),
755 6
            'defaultOffset' => $this->perPage,
756 6
        ] + $this->getIndexUrls($this->moduleName, $this->routePrefix);
757
758 6
        $baseUrl = $this->getPermalinkBaseUrl();
759
760
        $options = [
761 6
            'moduleName' => $this->moduleName,
762 6
            'reorder' => $this->getIndexOption('reorder'),
763 6
            'create' => $this->getIndexOption('create'),
764 6
            'translate' => $this->moduleHas('translations'),
765 6
            'translateTitle' => $this->titleIsTranslatable(),
766 6
            'permalink' => $this->getIndexOption('permalink'),
767 6
            'bulkEdit' => $this->getIndexOption('bulkEdit'),
768 6
            'titleFormKey' => $this->titleFormKey ?? $this->titleColumnKey,
769 6
            'baseUrl' => $baseUrl,
770 6
            'permalinkPrefix' => $this->getPermalinkPrefix($baseUrl),
771
        ];
772
773 6
        return array_replace_recursive($data + $options, $this->indexData($this->request));
774
    }
775
776
    /**
777
     * @param Request $request
778
     * @return array
779
     */
780 5
    protected function indexData($request)
781
    {
782 5
        return [];
783
    }
784
785
    /**
786
     * @param array $scopes
787
     * @param bool $forcePagination
788
     * @return \Illuminate\Database\Eloquent\Collection
789
     */
790 12
    protected function getIndexItems($scopes = [], $forcePagination = false)
791
    {
792 12
        return $this->transformIndexItems($this->repository->get(
793 12
            $this->indexWith,
794
            $scopes,
795 12
            $this->orderScope(),
796 12
            $this->request->get('offset') ?? $this->perPage ?? 50,
797
            $forcePagination
798
        ));
799
    }
800
801
    /**
802
     * @param \Illuminate\Database\Eloquent\Collection $items
803
     * @return \Illuminate\Database\Eloquent\Collection
804
     */
805 10
    protected function transformIndexItems($items)
806
    {
807 10
        return $items;
808
    }
809
810
    /**
811
     * @param \Illuminate\Database\Eloquent\Collection $items
812
     * @return array
813
     */
814 6
    protected function getIndexTableData($items)
815
    {
816 6
        $translated = $this->moduleHas('translations');
817
        return $items->map(function ($item) use ($translated) {
818
            $columnsData = Collection::make($this->indexColumns)->mapWithKeys(function ($column) use ($item) {
819 3
                return $this->getItemColumnData($item, $column);
820 3
            })->toArray();
821
822 3
            $name = $columnsData[$this->titleColumnKey];
823
824 3
            if (empty($name)) {
825
                if ($this->moduleHas('translations')) {
826
                    $fallBackTranslation = $item->translations()->where('active', true)->first();
827
828
                    if (isset($fallBackTranslation->{$this->titleColumnKey})) {
829
                        $name = $fallBackTranslation->{$this->titleColumnKey};
830
                    }
831
                }
832
833
                $name = $name ?? ('Missing ' . $this->titleColumnKey);
834
            }
835
836 3
            unset($columnsData[$this->titleColumnKey]);
837
838 3
            $itemIsTrashed = method_exists($item, 'trashed') && $item->trashed();
839 3
            $itemCanDelete = $this->getIndexOption('delete') && ($item->canDelete ?? true);
840 3
            $canEdit = $this->getIndexOption('edit');
841
842 3
            return array_replace([
843 3
                'id' => $item->id,
844 3
                'name' => $name,
845 3
                'publish_start_date' => $item->publish_start_date,
846 3
                'publish_end_date' => $item->publish_end_date,
847 3
                'edit' => $canEdit ? $this->getModuleRoute($item->id, 'edit') : null,
848 3
                'delete' => $itemCanDelete ? $this->getModuleRoute($item->id, 'destroy') : null,
849 3
            ] + ($this->getIndexOption('editInModal') ? [
850 1
                'editInModal' => $this->getModuleRoute($item->id, 'edit'),
851 1
                'updateUrl' => $this->getModuleRoute($item->id, 'update'),
852 3
            ] : []) + ($this->getIndexOption('publish') && ($item->canPublish ?? true) ? [
853 3
                'published' => $item->published,
854 3
            ] : []) + ($this->getIndexOption('feature') && ($item->canFeature ?? true) ? [
855
                'featured' => $item->{$this->featureField},
856 3
            ] : []) + (($this->getIndexOption('restore') && $itemIsTrashed) ? [
857
                'deleted' => true,
858 3
            ] : []) + ($translated ? [
859 3
                'languages' => $item->getActiveLanguages(),
860 3
            ] : []) + $columnsData, $this->indexItemData($item));
861 6
        })->toArray();
862
    }
863
864
    /**
865
     * @param \A17\Twill\Models\Model $item
866
     * @return array
867
     */
868 2
    protected function indexItemData($item)
869
    {
870 2
        return [];
871
    }
872
873
    /**
874
     * @param \A17\Twill\Models\Model $item
875
     * @param array $column
876
     * @return array
877
     */
878 5
    protected function getItemColumnData($item, $column)
879
    {
880 5
        if (isset($column['thumb']) && $column['thumb']) {
881 2
            if (isset($column['present']) && $column['present']) {
882
                return [
883
                    'thumbnail' => $item->presentAdmin()->{$column['presenter']},
884
                ];
885
            } else {
886 2
                $variant = isset($column['variant']);
887 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...
888 2
                $crop = $variant ? $column['variant']['crop'] : head(array_keys(head($item->mediasParams)));
889 2
                $params = $variant && isset($column['variant']['params'])
890
                ? $column['variant']['params']
891 2
                : ['w' => 80, 'h' => 80, 'fit' => 'crop'];
892
893
                return [
894 2
                    'thumbnail' => $item->cmsImage($role, $crop, $params),
895
                ];
896
            }
897
        }
898
899 5
        if (isset($column['nested']) && $column['nested']) {
900
            $field = $column['nested'];
901
            $nestedCount = $item->{$column['nested']}->count();
902
            $value = '<a href="';
903
            $value .= moduleRoute("$this->moduleName.$field", $this->routePrefix, 'index', [$item->id]);
904
            $value .= '">' . $nestedCount . " " . (strtolower($nestedCount > 1
905
                ? Str::plural($column['title'])
906
                : Str::singular($column['title']))) . '</a>';
907
        } else {
908 5
            $field = $column['field'];
909 5
            $value = $item->$field;
910
        }
911
912 5
        if (isset($column['relationship'])) {
913
            $field = $column['relationship'] . ucfirst($column['field']);
914
            $value = Arr::get($item, "{$column['relationship']}.{$column['field']}");
915 5
        } elseif (isset($column['present']) && $column['present']) {
916
            $value = $item->presentAdmin()->{$column['field']};
917
        }
918
919
        return [
920 5
            "$field" => $value,
921
        ];
922
    }
923
924
    /**
925
     * @param \Illuminate\Database\Eloquent\Collection $items
926
     * @return array
927
     */
928 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

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

1059
    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...
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

1059
    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...
1060
    {
1061 6
        return Collection::make([
1062 6
            'store',
1063
            'publish',
1064
            'bulkPublish',
1065
            'restore',
1066
            'bulkRestore',
1067
            'forceDelete',
1068
            'bulkForceDelete',
1069
            'reorder',
1070
            'feature',
1071
            'bulkFeature',
1072
            'bulkDelete',
1073
        ])->mapWithKeys(function ($endpoint) {
1074
            return [
1075 6
                $endpoint . 'Url' => $this->getIndexOption($endpoint) ? moduleRoute(
1076 6
                    $this->moduleName, $this->routePrefix, $endpoint,
1077 6
                    $this->submodule ? [$this->submoduleParentId] : []
1078
                ) : null,
1079
            ];
1080 6
        })->toArray();
1081
    }
1082
1083
    /**
1084
     * @param string $option
1085
     * @return bool
1086
     */
1087 29
    protected function getIndexOption($option)
1088
    {
1089
        return once(function () use ($option) {
1090
            $customOptionNamesMapping = [
1091 29
                'store' => 'create',
1092
            ];
1093
1094 29
            $option = array_key_exists($option, $customOptionNamesMapping) ? $customOptionNamesMapping[$option] : $option;
1095
1096
            $authorizableOptions = [
1097 29
                'create' => 'edit',
1098
                'edit' => 'edit',
1099
                'publish' => 'publish',
1100
                'feature' => 'feature',
1101
                'reorder' => 'reorder',
1102
                'delete' => 'delete',
1103
                'restore' => 'delete',
1104
                'forceDelete' => 'delete',
1105
                'bulkForceDelete' => 'delete',
1106
                'bulkPublish' => 'publish',
1107
                'bulkRestore' => 'delete',
1108
                'bulkFeature' => 'feature',
1109
                'bulkDelete' => 'delete',
1110
                'bulkEdit' => 'edit',
1111
                'editInModal' => 'edit',
1112
            ];
1113
1114 29
            $authorized = array_key_exists($option, $authorizableOptions) ? Auth::guard('twill_users')->user()->can($authorizableOptions[$option]) : true;
1115 29
            return ($this->indexOptions[$option] ?? $this->defaultIndexOptions[$option] ?? false) && $authorized;
1116 29
        });
1117
    }
1118
1119
    /**
1120
     * @param array $prependScope
1121
     * @return array
1122
     */
1123 2
    protected function getBrowserData($prependScope = [])
1124
    {
1125 2
        if ($this->request->has('except')) {
1126
            $prependScope['exceptIds'] = $this->request->get('except');
1127
        }
1128
1129 2
        $scopes = $this->filterScope($prependScope);
1130 2
        $items = $this->getBrowserItems($scopes);
1131 2
        $data = $this->getBrowserTableData($items);
1132
1133 2
        return array_replace_recursive(['data' => $data], $this->indexData($this->request));
1134
    }
1135
1136
    /**
1137
     * @param \Illuminate\Database\Eloquent\Collection $items
1138
     * @return array
1139
     */
1140 2
    protected function getBrowserTableData($items)
1141
    {
1142 2
        $withImage = $this->moduleHas('medias');
1143
1144
        return $items->map(function ($item) use ($withImage) {
1145
            $columnsData = Collection::make($this->browserColumns)->mapWithKeys(function ($column) use ($item) {
1146 2
                return $this->getItemColumnData($item, $column);
1147 2
            })->toArray();
1148
1149 2
            $name = $columnsData[$this->titleColumnKey];
1150 2
            unset($columnsData[$this->titleColumnKey]);
1151
1152
            return [
1153 2
                'id' => $item->id,
1154 2
                'name' => $name,
1155 2
                'edit' => moduleRoute($this->moduleName, $this->routePrefix, 'edit', $item->id),
1156 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

1156
                'endpointType' => $this->repository->/** @scrutinizer ignore-call */ getMorphClass(),
Loading history...
1157 2
            ] + $columnsData + ($withImage && !array_key_exists('thumbnail', $columnsData) ? [
1158 2
                'thumbnail' => $item->defaultCmsImage(['w' => 100, 'h' => 100]),
1159 2
            ] : []);
1160 2
        })->toArray();
1161
    }
1162
1163
    /**
1164
     * @param array $scopes
1165
     * @return \Illuminate\Database\Eloquent\Collection
1166
     */
1167 2
    protected function getBrowserItems($scopes = [])
1168
    {
1169 2
        return $this->getIndexItems($scopes, true);
1170
    }
1171
1172
    /**
1173
     * @param array $prepend
1174
     * @return array
1175
     */
1176 12
    protected function filterScope($prepend = [])
1177
    {
1178 12
        $scope = [];
1179
1180 12
        $requestFilters = $this->getRequestFilters();
1181
1182 12
        $this->filters = array_merge($this->filters, $this->defaultFilters);
1183
1184 12
        if (array_key_exists('status', $requestFilters)) {
1185 1
            switch ($requestFilters['status']) {
1186 1
                case 'published':
1187 1
                    $scope['published'] = true;
1188 1
                    break;
1189
                case 'draft':
1190
                    $scope['draft'] = true;
1191
                    break;
1192
                case 'trash':
1193
                    $scope['onlyTrashed'] = true;
1194
                    break;
1195
                case 'mine':
1196
                    $scope['mine'] = true;
1197
                    break;
1198
            }
1199
1200 1
            unset($requestFilters['status']);
1201
        }
1202
1203 12
        foreach ($this->filters as $key => $field) {
1204 12
            if (array_key_exists($key, $requestFilters)) {
1205 2
                $value = $requestFilters[$key];
1206 2
                if ($value == 0 || !empty($value)) {
1207
                    // add some syntaxic sugar to scope the same filter on multiple columns
1208 2
                    $fieldSplitted = explode('|', $field);
1209 2
                    if (count($fieldSplitted) > 1) {
1210
                        $requestValue = $requestFilters[$key];
1211
                        Collection::make($fieldSplitted)->each(function ($scopeKey) use (&$scope, $requestValue) {
1212
                            $scope[$scopeKey] = $requestValue;
1213
                        });
1214
                    } else {
1215 2
                        $scope[$field] = $requestFilters[$key];
1216
                    }
1217
                }
1218
            }
1219
        }
1220
1221 12
        return $prepend + $scope;
1222
    }
1223
1224
    /**
1225
     * @return array
1226
     */
1227 7
    protected function getRequestFilters()
1228
    {
1229 7
        if ($this->request->has('search')) {
1230
            return ['search' => $this->request->get('search')];
1231
        }
1232
1233 7
        return json_decode($this->request->get('filter'), true) ?? [];
1234
    }
1235
1236
    /**
1237
     * @return array
1238
     */
1239 12
    protected function orderScope()
1240
    {
1241 12
        $orders = [];
1242 12
        if ($this->request->has('sortKey') && $this->request->has('sortDir')) {
1243 1
            if (($key = $this->request->get('sortKey')) == 'name') {
1244
                $sortKey = $this->titleColumnKey;
1245 1
            } elseif (!empty($key)) {
1246 1
                $sortKey = $key;
1247
            }
1248
1249 1
            if (isset($sortKey)) {
1250 1
                $orders[$this->indexColumns[$sortKey]['sortKey'] ?? $sortKey] = $this->request->get('sortDir');
1251
            }
1252
        }
1253
1254
        // don't apply default orders if reorder is enabled
1255 12
        $reorder = $this->getIndexOption('reorder');
1256 12
        $defaultOrders = ($reorder ? [] : ($this->defaultOrders ?? []));
1257
1258 12
        return $orders + $defaultOrders;
1259
    }
1260
1261
    /**
1262
     * @param int $id
1263
     * @param \A17\Twill\Models\Model|null $item
1264
     * @return array
1265
     */
1266 4
    protected function form($id, $item = null)
1267
    {
1268 4
        $item = $item ?? $this->repository->getById($id, $this->formWith, $this->formWithCount);
1269
1270 4
        $fullRoutePrefix = 'admin.' . ($this->routePrefix ? $this->routePrefix . '.' : '') . $this->moduleName . '.';
1271 4
        $previewRouteName = $fullRoutePrefix . 'preview';
1272 4
        $restoreRouteName = $fullRoutePrefix . 'restoreRevision';
1273
1274 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...
1275
1276
        $data = [
1277 4
            'item' => $item,
1278 4
            'moduleName' => $this->moduleName,
1279 4
            'routePrefix' => $this->routePrefix,
1280 4
            'titleFormKey' => $this->titleFormKey ?? $this->titleColumnKey,
1281 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...
1282 4
            'translate' => $this->moduleHas('translations'),
1283 4
            'permalink' => $this->getIndexOption('permalink'),
1284 4
            'form_fields' => $this->repository->getFormFields($item),
1285 4
            'baseUrl' => $baseUrl,
1286 4
            'permalinkPrefix' => $this->getPermalinkPrefix($baseUrl),
1287 4
            'saveUrl' => $this->getModuleRoute($item->id, 'update'),
1288 4
            'editor' => $this->moduleHas('revisions') && $this->moduleHas('blocks') && !$this->disableEditor,
1289 4
            'blockPreviewUrl' => Route::has('admin.blocks.preview') ? URL::route('admin.blocks.preview') : '#',
1290 4
            'revisions' => $this->moduleHas('revisions') ? $item->revisionsArray() : null,
1291 4
        ] + (Route::has($previewRouteName) ? [
1292 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

1292
            'previewUrl' => moduleRoute($this->moduleName, $this->routePrefix, 'preview', /** @scrutinizer ignore-type */ $item->id),
Loading history...
1293 4
        ] : [])
1294 4
             + (Route::has($restoreRouteName) ? [
1295 4
            'restoreUrl' => moduleRoute($this->moduleName, $this->routePrefix, 'restoreRevision', $item->id),
1296 4
        ] : []);
1297
1298 4
        return array_replace_recursive($data, $this->formData($this->request));
1299
    }
1300
1301
    /**
1302
     * @param int $id
1303
     * @return array
1304
     */
1305 1
    protected function modalFormData($id)
1306
    {
1307 1
        $item = $this->repository->getById($id, $this->formWith, $this->formWithCount);
1308 1
        $fields = $this->repository->getFormFields($item);
1309 1
        $data = [];
1310
1311 1
        if ($this->moduleHas('translations') && isset($fields['translations'])) {
1312 1
            foreach ($fields['translations'] as $fieldName => $fieldValue) {
1313 1
                $data['fields'][] = [
1314 1
                    'name' => $fieldName,
1315 1
                    'value' => $fieldValue,
1316
                ];
1317
            }
1318
1319 1
            $data['languages'] = $item->getActiveLanguages();
1320
1321 1
            unset($fields['translations']);
1322
        }
1323
1324 1
        foreach ($fields as $fieldName => $fieldValue) {
1325 1
            $data['fields'][] = [
1326 1
                'name' => $fieldName,
1327 1
                'value' => $fieldValue,
1328
            ];
1329
        }
1330
1331 1
        return array_replace_recursive($data, $this->formData($this->request));
1332
    }
1333
1334
    /**
1335
     * @param Request $request
1336
     * @return array
1337
     */
1338 4
    protected function formData($request)
1339
    {
1340 4
        return [];
1341
    }
1342
1343
    /**
1344
     * @param Request $item
1345
     * @return array
1346
     */
1347 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

1347
    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...
1348
    {
1349 1
        return [];
1350
    }
1351
1352
    /**
1353
     * @return \A17\Twill\Http\Requests\Admin\Request
1354
     */
1355 21
    protected function validateFormRequest()
1356
    {
1357
        $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

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