Completed
Push — master ( f9b7df...d2a791 )
by Yaro
05:43 queued 11s
created

AbstractTableController::getListViewsBelow()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Yaro\Jarboe\Http\Controllers;
4
5
use Illuminate\Foundation\Http\FormRequest;
6
use Illuminate\Foundation\Validation\ValidatesRequests;
7
use Illuminate\Http\Request;
8
use Illuminate\Support\Facades\Request as RequestFacade;
9
use Illuminate\Validation\ValidationException;
10
use Spatie\Permission\Exceptions\UnauthorizedException;
11
use Yaro\Jarboe\Exceptions\PermissionDenied;
12
use Yaro\Jarboe\Table\Actions\AbstractAction;
13
use Yaro\Jarboe\Table\Actions\CreateAction;
14
use Yaro\Jarboe\Table\Actions\DeleteAction;
15
use Yaro\Jarboe\Table\Actions\EditAction;
16
use Yaro\Jarboe\Table\Actions\ForceDeleteAction;
17
use Yaro\Jarboe\Table\Actions\RestoreAction;
18
use Yaro\Jarboe\Table\CRUD;
19
use Yaro\Jarboe\Table\Fields\AbstractField;
20
use Yaro\Jarboe\Table\Fields\Select;
21
use Yaro\Jarboe\Table\Toolbar\Interfaces\ToolInterface;
22
use Yaro\Jarboe\Table\Toolbar\TranslationLocalesSelectorTool;
23
24
abstract class AbstractTableController
25
{
26
    use ValidatesRequests;
27
28
    protected $viewCrudList = 'jarboe::crud.list';
29
    protected $viewCrudCreate = 'jarboe::crud.create';
30
    protected $viewCrudEdit = 'jarboe::crud.edit';
31
32
    /**
33
     * Permission group name.
34
     *
35
     * @var string|array
36
     * array(
37
     *     'list'        => 'permission:list',
38
     *     'search'      => 'permission:search',
39
     *     'create'      => 'permission:create',
40
     *     'store'       => 'permission:store',
41
     *     'edit'        => 'permission:edit',
42
     *     'update'      => 'permission:update',
43
     *     'inline'      => 'permission:inline',
44
     *     'delete'      => 'permission:delete',
45
     *     'restore'     => 'permission:restore',
46
     *     'forceDelete' => 'permission:force-delete',
47
     * )
48
     */
49
    protected $permissions = '';
50
51
    /**
52
     * @var CRUD
53
     */
54
    protected $crud;
55
56
    /**
57
     * ID of manipulated model.
58
     *
59
     * @var mixed
60
     */
61
    protected $idEntity;
62
63 17
    public function __construct()
64
    {
65 17
        $this->crud = app(CRUD::class);
66 17
        $this->crud()->tableIdentifier(crc32(static::class));
67 17
        $this->crud()->formClass(config('jarboe.crud.form_class'));
68 17
        $this->crud()->actions()->set([
69 17
            CreateAction::make(),
70 17
            EditAction::make(),
71 17
            RestoreAction::make(),
72 17
            DeleteAction::make(),
73 17
            ForceDeleteAction::make(),
74
        ]);
75 17
    }
76
77
    protected function crud(): CRUD
78
    {
79
        return $this->crud;
80
    }
81
82
    /**
83
     * Handle search action.
84
     *
85
     * @param Request $request
86
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
87
     * @throws UnauthorizedException
88
     */
89 1
    public function handleSearch(Request $request)
90
    {
91 1
        $this->init();
92 1
        $this->bound();
93
94 1
        if (!$this->can('search')) {
95
            throw UnauthorizedException::forPermissions(['search']);
96
        }
97
98 1
        $this->crud()->saveSearchFilterParams($request->get('search', []));
99
100 1
        return redirect($this->crud()->listUrl());
101
    }
102
103
    /**
104
     * Handle relation search action.
105
     * Currently used for SelectField with type `select2` and `ajax = true`.
106
     *
107
     * @param string $field
0 ignored issues
show
Bug introduced by
There is no parameter named $field. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
108
     * @param string $page
0 ignored issues
show
Bug introduced by
There is no parameter named $page. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
109
     * @param string $term
0 ignored issues
show
Bug introduced by
There is no parameter named $term. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
110
     * @return \Illuminate\Http\JsonResponse
111
     */
112
    public function searchRelation(Request $request)
113
    {
114
        $this->init();
115
        $this->bound();
116
117
        // TODO:
118
        $perPage = 10;
119
120
        $query = $request->get('term');
121
        $fieldName = $request->get('field');
122
        $page = (int) $request->get('page');
123
124
        /** @var Select $field */
125
        $field = $this->crud()->getFieldByName($fieldName);
126
        if (!$field) {
127
            throw new \RuntimeException(sprintf('Field [%s] not setted to crud', $fieldName));
128
        }
129
130
        $total = 0;
131
        $results = [];
132
        if ($field->isGroupedRelation()) {
133
            foreach ($field->getRelations() as $index => $group) {
134
                $options = $field->getOptions($page, $perPage, $query, $total, $index);
135
                array_walk($options, function (&$item, $key) use ($group) {
136
                    $item = [
137
                        'id'   => crc32($group['group']) .'~~~'. $key,
138
                        'text' => $item,
139
                    ];
140
                });
141
                if ($options) {
142
                    $results[] = [
143
                        'text'     => $group['group'],
144
                        'children' => array_values($options),
145
                    ];
146
                }
147
            }
148
        } else {
149
            $results = $field->getOptions($page, $perPage, $query, $total);
150
            array_walk($results, function (&$item, $key) {
151
                $item = [
152
                    'id'   => $key,
153
                    'text' => $item,
154
                ];
155
            });
156
        }
157
158
        return response()->json([
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
159
            'results' => array_values($results),
160
            'pagination' => [
161
                'more' => $total > $page * $perPage,
162
            ]
163
        ]);
164
    }
165
166
    /**
167
     * Save direction by column.
168
     *
169
     * @param $column
170
     * @param $direction
171
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
172
     */
173 1
    public function orderBy($column, $direction)
174
    {
175 1
        $this->crud()->saveOrderFilterParam($column, $direction);
176
177 1
        return redirect($this->crud()->listUrl());
178
    }
179
180
    /**
181
     * Handle store action.
182
     *
183
     * @param Request $request
184
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
185
     * @throws PermissionDenied
186
     * @throws UnauthorizedException
187
     */
188 1
    public function handleStore(Request $request)
189
    {
190 1
        $this->init();
191 1
        $this->bound();
192
193 1
        if (!$this->crud()->actions()->isAllowed('create')) {
194
            throw new PermissionDenied();
195
        }
196
197 1
        if (!$this->can('store')) {
198
            throw UnauthorizedException::forPermissions(['store']);
199
        }
200
201 1
        $model = $this->crud()->repo()->store($request);
202 1
        $this->idEntity = $model->getKey();
203
204 1
        return redirect($this->crud()->listUrl());
205
    }
206
207
    /**
208
     * Handle inline update action.
209
     *
210
     * @param Request $request
211
     * @return \Illuminate\Http\JsonResponse
212
     * @throws PermissionDenied
213
     * @throws \ReflectionException
214
     */
215 1
    public function handleInline(Request $request)
216
    {
217 1
        $this->init();
218 1
        $this->bound();
219
220 1
        if (!$this->can('inline')) {
221
            throw UnauthorizedException::forPermissions(['inline']);
222
        }
223
224 1
        $id = $request->get('_pk');
225 1
        $value = $request->get('_value');
226
        /** @var AbstractField $field */
227 1
        $field = $this->crud()->getFieldByName($request->get('_name'));
228 1
        $locale = $request->get('_locale');
229
230 1
        $model = $this->crud()->repo()->find($id);
231 1
        if ((!$field->isInline() && !$this->crud()->actions()->isAllowed('edit', $model)) || $field->isReadonly()) {
232
            throw new PermissionDenied();
233
        }
234
235 1
        if (method_exists($this, 'update')) {
236
            list($rules, $messages, $attributes) = $this->getValidationDataForInlineField($request, $field->name());
237
            if ($rules) {
238
                $this->validate(
239
                    $request,
240
                    [$field->name() => $rules],
241
                    $messages,
242
                    $attributes
243
                );
244
            }
245
        }
246
247
        // change app locale, so translatable model's column will be set properly
248 1
        if ($locale) {
249
            app()->setLocale($locale);
250
        }
251
252 1
        $model = $this->crud()->repo()->updateField($id, $request, $field, $value);
253 1
        $this->idEntity = $model->getKey();
254
255 1
        return response()->json([
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
256 1
            'value' => $model->{$field->name()},
257
        ]);
258
    }
259
260
    /**
261
     * Get validation data for inline field.
262
     *
263
     * @param Request $request
264
     * @param $name
265
     * @return array
266
     * @throws \ReflectionException
267
     */
268
    protected function getValidationDataForInlineField(Request $request, $name)
269
    {
270
        $rules = [];
271
        $messages = [];
272
        $attributes = [];
273
274
        $reflection = new \ReflectionClass(get_class($this));
275
        $method = $reflection->getMethod('update');
276
        $parameters = $method->getParameters();
277
        $firstParam = $parameters[0] ?? null;
278
        $isRequestAsFirstParameter = $firstParam && $firstParam->getClass();
279
        if ($isRequestAsFirstParameter) {
280
            $formRequestClass = $firstParam->getClass()->getName();
281
            /** @var FormRequest $formRequest */
282
            $formRequest = new $formRequestClass();
283
            if (method_exists($formRequest, 'rules')) {
284
                foreach ($formRequest->rules() as $param => $paramRules) {
285
                    if (preg_match('~^'. preg_quote($name) .'(\.\*)?$~', $param)) {
286
                        return [
287
                            $paramRules,
288
                            $formRequest->messages(),
289
                            $formRequest->attributes(),
290
                        ];
291
                    }
292
                }
293
            }
294
        }
295
296
        return [$rules, $messages, $attributes];
297
    }
298
299
    /**
300
     * Handle update action.
301
     *
302
     * @param Request $request
303
     * @param $id
304
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
305
     * @throws PermissionDenied
306
     * @throws UnauthorizedException
307
     */
308 1
    public function handleUpdate(Request $request, $id)
309
    {
310 1
        $this->init();
311 1
        $this->bound();
312
313 1
        $model = $this->crud()->repo()->find($id);
314 1
        if (!$this->crud()->actions()->isAllowed('edit', $model)) {
315
            throw new PermissionDenied();
316
        }
317
318 1
        if (!$this->can('update')) {
319
            throw UnauthorizedException::forPermissions(['update']);
320
        }
321
322 1
        $this->crud()->repo()->update($id, $request);
323 1
        $this->idEntity = $model->getKey();
324
325 1
        return redirect($this->crud()->listUrl());
326
    }
327
328
    /**
329
     * Handle delete action.
330
     *
331
     * @param Request $request
332
     * @param $id
333
     * @return \Illuminate\Http\JsonResponse
334
     * @throws PermissionDenied
335
     * @throws UnauthorizedException
336
     */
337 1
    public function handleDelete(Request $request, $id)
338
    {
339 1
        $this->init();
340 1
        $this->bound();
341
342 1
        $model = $this->crud()->repo()->find($id);
343 1
        if (!$this->crud()->actions()->isAllowed('delete', $model)) {
344
            throw new PermissionDenied();
345
        }
346
347 1
        if (!$this->can('delete')) {
348
            throw UnauthorizedException::forPermissions(['delete']);
349
        }
350
351 1
        $this->idEntity = $model->getKey();
352
353 1
        if ($this->crud()->repo()->delete($id)) {
354 1
            $type = 'hidden';
355
            try {
356 1
                $this->crud()->repo()->find($id);
357
            } catch (\Exception $e) {
358
                $type = 'removed';
359
            }
360
361 1
            return response()->json([
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
362 1
                'type' => $type,
363 1
                'message' => __('jarboe::common.list.delete_success_message', ['id' => $id]),
364
            ]);
365
        }
366
367
        return response()->json([
368
            'message' => __('jarboe::common.list.delete_failed_message', ['id' => $id]),
369
        ], 422);
370
    }
371
372
    /**
373
     * Handle setting per page param.
374
     *
375
     * @param $perPage
376
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
377
     */
378 1
    public function perPage($perPage)
379
    {
380 1
        $this->init();
381 1
        $this->bound();
382
383 1
        $this->crud()->setPerPageParam((int) $perPage);
384
385 1
        return redirect($this->crud()->listUrl());
386
    }
387
388
    /**
389
     * Show table list page.
390
     *
391
     * @param Request $request
392
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
393
     * @throws UnauthorizedException
394
     */
395 1 View Code Duplication
    public function handleList(Request $request)
396
    {
397 1
        $this->init();
398 1
        $this->bound();
399
400 1
        if (!$this->can('list')) {
401
            throw UnauthorizedException::forPermissions(['list']);
402
        }
403
404 1
        return view($this->viewCrudList, [
405 1
            'crud' => $this->crud,
406 1
            'items' => $this->crud()->repo()->get(),
407 1
            'viewsAbove' => $this->getListViewsAbove(),
408 1
            'viewsBelow' => $this->getListViewsBelow(),
409
        ]);
410
    }
411
412
    /**
413
     * Get array of view's objects, that should be rendered above content of `list` view.
414
     *
415
     * @return array
416
     */
417 2
    protected function getListViewsAbove(): array
418
    {
419 2
        return [];
420
    }
421
422
    /**
423
     * Get array of view's objects, that should be rendered below content of `list` view.
424
     *
425
     * @return array
426
     */
427 2
    protected function getListViewsBelow(): array
428
    {
429 2
        return [];
430
    }
431
432
    /**
433
     * Show edit form page.
434
     *
435
     * @param Request $request
436
     * @param $id
437
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
438
     * @throws PermissionDenied
439
     * @throws UnauthorizedException
440
     */
441 1
    public function handleEdit(Request $request, $id)
442
    {
443 1
        $this->init();
444 1
        $this->bound();
445
446 1
        $model = $this->crud()->repo()->find($id);
447 1
        if (!$this->crud()->actions()->isAllowed('edit', $model)) {
448
            throw new PermissionDenied();
449
        }
450
451 1
        if (!$this->can('edit')) {
452
            throw UnauthorizedException::forPermissions(['edit']);
453
        }
454
455 1
        $this->idEntity = $model->getKey();
456
457 1
        return view($this->viewCrudEdit, [
458 1
            'crud' => $this->crud,
459 1
            'item' => $model,
460 1
            'viewsAbove' => $this->getEditViewsAbove(),
461 1
            'viewsBelow' => $this->getEditViewsBelow(),
462
        ]);
463
    }
464
465
    /**
466
     * Get array of view's objects, that should be rendered above content of `edit` view.
467
     *
468
     * @return array
469
     */
470 2
    protected function getEditViewsAbove(): array
471
    {
472 2
        return [];
473
    }
474
475
    /**
476
     * Get array of view's objects, that should be rendered below content of `edit` view.
477
     *
478
     * @return array
479
     */
480 2
    protected function getEditViewsBelow(): array
481
    {
482 2
        return [];
483
    }
484
485
    /**
486
     * Show create form page.
487
     *
488
     * @param Request $request
489
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
490
     * @throws PermissionDenied
491
     * @throws UnauthorizedException
492
     */
493 1 View Code Duplication
    public function handleCreate(Request $request)
494
    {
495 1
        $this->init();
496 1
        $this->bound();
497
498 1
        if (!$this->crud()->actions()->isAllowed('create')) {
499
            throw new PermissionDenied();
500
        }
501
502 1
        if (!$this->can('create')) {
503
            throw UnauthorizedException::forPermissions(['create']);
504
        }
505
506 1
        return view($this->viewCrudCreate, [
507 1
            'crud' => $this->crud,
508 1
            'viewsAbove' => $this->getCreateViewsAbove(),
509 1
            'viewsBelow' => $this->getCreateViewsBelow(),
510
        ]);
511
    }
512
513
    /**
514
     * Get array of view's objects, that should be rendered above content of `create` view.
515
     *
516
     * @return array
517
     */
518 2
    protected function getCreateViewsAbove(): array
519
    {
520 2
        return [];
521
    }
522
523
    /**
524
     * Get array of view's objects, that should be rendered below content of `create` view.
525
     *
526
     * @return array
527
     */
528 2
    protected function getCreateViewsBelow(): array
529
    {
530 2
        return [];
531
    }
532
533
    /**
534
     * Handle toolbar's tool request.
535
     *
536
     * @param Request $request
537
     * @param $identifier
538
     * @return mixed
539
     * @throws PermissionDenied
540
     */
541
    public function toolbar(Request $request, $identifier)
542
    {
543
        $this->init();
544
        $this->bound();
545
546
        /** @var ToolInterface $tool */
547
        $tool = $this->crud()->getTool($identifier);
548
        if (!$tool->check()) {
549
            throw new PermissionDenied();
550
        }
551
552
        return $tool->handle($request);
553
    }
554
555
    /**
556
     * Switch table order for making sortable table.
557
     *
558
     * @return \Illuminate\Http\RedirectResponse
559
     * @throws PermissionDenied
560
     */
561
    public function switchSortable()
562
    {
563
        $this->init();
564
        $this->bound();
565
566
        if (!$this->crud()->isSortableByWeight()) {
567
            throw new PermissionDenied();
568
        }
569
570
        $newState = !$this->crud()->isSortableByWeightActive();
571
        $this->crud()->setSortableOrderState($newState);
572
573
        return back();
574
    }
575
576
    /**
577
     * Change sort weight of dragged row.
578
     *
579
     * @param $id
580
     * @param Request $request
581
     * @return \Illuminate\Http\JsonResponse
582
     * @throws PermissionDenied
583
     */
584
    public function moveItem($id, Request $request)
585
    {
586
        $this->init();
587
        $this->bound();
588
589
        if (!$this->crud()->isSortableByWeight()) {
590
            throw new PermissionDenied();
591
        }
592
593
        $this->crud()->repo()->reorder($id, $request->get('prev'), $request->get('next'));
594
595
        return response()->json([
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
596
            'ok' => true,
597
        ]);
598
    }
599
600
    /**
601
     * Restore record by its id.
602
     *
603
     * @param $id
604
     * @param Request $request
605
     * @return \Illuminate\Http\JsonResponse
606
     * @throws PermissionDenied
607
     * @throws UnauthorizedException
608
     */
609 1 View Code Duplication
    public function handleRestore(Request $request, $id)
610
    {
611 1
        $this->init();
612 1
        $this->bound();
613
614 1
        if (!$this->crud()->isSoftDeleteEnabled()) {
615
            throw new PermissionDenied();
616
        }
617
618 1
        if (!$this->can('restore')) {
619
            throw UnauthorizedException::forPermissions(['restore']);
620
        }
621
622 1
        $model = $this->crud()->repo()->find($id);
623 1
        if ($this->crud()->repo()->restore($id) || !$model->trashed()) {
624 1
            return response()->json([
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
625 1
                'message' => __('jarboe::common.list.restore_success_message', ['id' => $id]),
626
            ]);
627
        }
628
629
        $this->idEntity = $model->getKey();
630
631
        return response()->json([
632
            'message' => __('jarboe::common.list.restore_failed_message', ['id' => $id]),
633
        ], 422);
634
    }
635
636
    /**
637
     * Force delete record by its id.
638
     *
639
     * @param $id
640
     * @param Request $request
641
     * @return \Illuminate\Http\JsonResponse
642
     * @throws PermissionDenied
643
     * @throws UnauthorizedException
644
     */
645 1 View Code Duplication
    public function handleForceDelete(Request $request, $id)
646
    {
647 1
        $this->init();
648 1
        $this->bound();
649
650 1
        $model = $this->crud()->repo()->find($id);
651 1
        if (!$this->crud()->isSoftDeleteEnabled() || !$model->trashed()) {
652
            throw new PermissionDenied();
653
        }
654
655 1
        if (!$this->can('force-delete')) {
656
            throw UnauthorizedException::forPermissions(['force-delete']);
657
        }
658
659 1
        if ($this->crud()->repo()->forceDelete($id)) {
660 1
            return response()->json([
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
661 1
                'message' => __('jarboe::common.list.force_delete_success_message', ['id' => $id]),
662
            ]);
663
        }
664
665
        return response()->json([
666
            'message' => __('jarboe::common.list.force_delete_failed_message', ['id' => $id]),
667
        ], 422);
668
    }
669
670
    /*
671
    |--------------------------------------------------------------------------
672
    | Helpers
673
    |--------------------------------------------------------------------------
674
    */
675 1
    protected function addTools(array $tools)
676
    {
677 1
        foreach ($tools as $tool) {
678 1
            $this->addTool($tool);
679
        }
680 1
    }
681
682 2
    protected function addTool(ToolInterface $tool)
683
    {
684 2
        $tool->setCrud($this->crud);
685 2
        $this->crud()->addTool($tool);
686 2
    }
687
688
    /**
689
     * @param string|AbstractField $column
690
     */
691
    protected function addColumn($column)
692
    {
693
        $this->crud()->addColumn($column);
694
    }
695
696
    protected function addColumns(array $columns)
697
    {
698
        foreach ($columns as $column) {
699
            $this->addColumn($column);
700
        }
701
    }
702
703 13
    protected function addField(AbstractField $field)
704
    {
705 13
        $this->crud()->addField($field);
706 13
    }
707
708 13
    protected function addFields(array $fields)
709
    {
710 13
        foreach ($fields as $field) {
711 13
            $this->addField($field);
712
        }
713 13
    }
714
715
    protected function addTab($title, array $fields)
716
    {
717
        foreach ($fields as $field) {
718
            $field->tab($title);
719
            $this->addField($field);
720
        }
721
    }
722
723 13
    protected function setModel($model)
724
    {
725 13
        $this->crud()->setModel($model);
726 13
    }
727
728
    protected function paginate($perPage)
729
    {
730
        $this->crud()->paginate($perPage);
731
    }
732
733
    protected function order(string $column, string $direction = 'asc')
734
    {
735
        $this->crud()->order($column, $direction);
736
    }
737
738 13
    protected function filter(\Closure $callback)
739
    {
740 13
        $this->crud()->filter($callback);
741 13
    }
742
743
    protected function action($ident)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
744
    {
745
        return $this->crud()->actions()->find($ident);
746
    }
747
748
    protected function removeAction($ident)
749
    {
750
        $this->crud()->actions()->remove($ident);
751
    }
752
753
    public function enableBatchCheckboxes(bool $enabled = true)
754
    {
755
        $this->crud()->enableBatchCheckboxes($enabled);
756
    }
757
758
    /**
759
     * Enable soft deletes for table.
760
     *
761
     * @param bool $enabled
762
     */
763 13
    public function softDeletes(bool $enabled = true)
764
    {
765 13
        $this->crud()->enableSoftDelete($enabled);
766 13
    }
767
768
    /**
769
     * Allows to reorder table rows.
770
     *
771
     * @param string $field
772
     */
773
    public function sortable(string $field)
774
    {
775
        $this->crud()->enableSortableByWeight($field);
776
    }
777
778
    /**
779
     * Add row action button with optional changing order.
780
     *
781
     * @param AbstractAction $action
782
     * @param null|string $moveDirection Move action 'before' or 'after' $baseActionIdent
783
     * @param null|string $baseActionIdent
784
     */
785
    protected function addAction(AbstractAction $action, $moveDirection = null, $baseActionIdent = null)
786
    {
787
        $this->crud()->actions()->add($action);
788
        if (!is_null($moveDirection) && !is_null($baseActionIdent)) {
789
            if ($moveDirection == 'after') {
790
                $this->crud()->actions()->moveAfter($baseActionIdent, $action->identifier());
791
            } else {
792
                $this->crud()->actions()->moveBefore($baseActionIdent, $action->identifier());
793
            }
794
        }
795
    }
796
797
    protected function addActions(array $actions)
798
    {
799
        $this->crud()->actions()->add($actions);
800
    }
801
802
    protected function setActions(array $actions = [])
803
    {
804
        $this->crud()->actions()->set($actions);
805
    }
806
807
    /**
808
     * Check if user has permission for the action.
809
     *
810
     * @param $action
811
     * @return bool
812
     */
813 11
    protected function can($action): bool
814
    {
815 11
        if (!$this->permissions) {
816 11
            return true;
817
        }
818
        if (is_array($this->permissions) && !array_key_exists($action, $this->permissions)) {
819
            return true;
820
        }
821
822
        if (is_array($this->permissions)) {
823
            $permission = $this->permissions[$action];
824
        } else {
825
            $permission = sprintf('%s:%s', $this->permissions, $action);
826
        }
827
828
        return admin_user()->can($permission);
829
    }
830
831
    /**
832
     * Get admin user object.
833
     *
834
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
835
     */
836
    protected function admin()
837
    {
838
        return admin_user();
839
    }
840
841
    /**
842
     * Add locales for all translatable fields.
843
     *
844
     * @param array $locales
845
     */
846
    protected function locales(array $locales)
847
    {
848
        $this->crud()->locales($locales);
849
    }
850
851 10
    public function __call($name, $arguments)
852
    {
853
        /** @var Request $request */
854 10
        $request = RequestFacade::instance();
855
856 10
        $id = null;
857 10
        if (isset($arguments[0])) {
858 9
            $id = $arguments[1] ?? $arguments[0];
859
        }
860
861
        try {
862 10
            switch ($name) {
863 10
                case 'list':
864 1
                    return $this->handleList($request);
865 9
                case 'search':
866 1
                    return $this->handleSearch($request);
867 8
                case 'create':
868 1
                    return $this->handleCreate($request);
869 7
                case 'store':
870 1
                    return $this->handleStore($request);
871 6
                case 'edit':
872 1
                    return $this->handleEdit($request, $id);
873 5
                case 'update':
874 1
                    return $this->handleUpdate($request, $id);
875 4
                case 'delete':
876 1
                    return $this->handleDelete($request, $id);
877 3
                case 'restore':
878 1
                    return $this->handleRestore($request, $id);
879 2
                case 'forceDelete':
880 1
                    return $this->handleForceDelete($request, $id);
881 1
                case 'inline':
882 1
                    return $this->handleInline($request);
883
884
                default:
885
                    throw new \RuntimeException('Invalid method ' . $name);
886
            }
887
        } catch (ValidationException $e) {
888
            throw $e;
889
        } catch (UnauthorizedException $e) {
890
            return $this->createUnauthorizedResponse($request, $e);
891
        } catch (\Exception $e) {
892
            $this->notifyBigDanger(get_class($e), $e->getMessage(), 0);
893
            return redirect()->back()->withInput($request->input());
894
        }
895
    }
896
897
    /**
898
     * Bound fields/tools/etc with global data.
899
     */
900 13
    protected function bound()
901
    {
902
        /** @var AbstractField $field */
903 13
        foreach ($this->crud()->getAllFieldObjects() as $field) {
904 13
            $field->prepare($this->crud);
905
        }
906
907
        /** @var AbstractField $field */
908 13
        foreach ($this->crud()->getFieldsWithoutMarkup() as $field) {
909 13
            if ($field->isTranslatable()) {
910
                $this->addTool(new TranslationLocalesSelectorTool());
911
                break;
912
            }
913
        }
914
915 13
        $this->crud()->actions()->setCrud($this->crud());
916 13
    }
917
918
    /**
919
     * Create response for unauthorized request.
920
     *
921
     * @param Request $request
922
     * @param UnauthorizedException $exception
923
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\JsonResponse|\Illuminate\View\View
924
     */
925
    protected function createUnauthorizedResponse(Request $request, UnauthorizedException $exception)
926
    {
927
        if ($request->wantsJson()) {
928
            return response()->json([
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
929
                'message' => $exception->getMessage()
930
            ], 401);
931
        }
932
933
        return view('jarboe::errors.401');
934
    }
935
936
    /**
937
     * Get model for current request.
938
     *
939
     * @return string
940
     * @throws \RuntimeException
941
     */
942
    protected function model()
943
    {
944
        if (!$this->idEntity) {
945
            throw new \RuntimeException('Trying to access to non-existed entity');
946
        }
947
948
        return $this->crud()->repo()->find($this->idEntity);
949
    }
950
951
    /**
952
     * Add notification.
953
     *
954
     * @param string $title
955
     * @param string|null $content
956
     * @param int $timeout
957
     * @param string|null $color
958
     * @param string|null $icon
959
     * @param string $type
960
     */
961 1
    protected function notify(string $title, string $content = null, int $timeout = 4000, string $color = null, string $icon = null, string $type = 'small')
962
    {
963 1
        $ident = 'jarboe_notifications.'. $type;
964
965 1
        $messages = session()->get($ident, []);
966 1
        $messages[] = [
967 1
            'title' => $title,
968 1
            'content' => $content,
969 1
            'color' => $color,
970 1
            'icon' => $icon,
971 1
            'timeout' => $timeout,
972
        ];
973
974 1
        session()->flash($ident, $messages);
975 1
    }
976
977
    protected function notifySmall(string $title, string $content = null, int $timeout = 4000, string $color = null, string $icon = null)
978
    {
979
        $this->notify($title, $content, $timeout, $color, $icon, 'small');
980
    }
981
982
    protected function notifyBig(string $title, string $content = null, int $timeout = 4000, string $color = null, string $icon = null)
983
    {
984
        $this->notify($title, $content, $timeout, $color, $icon, 'big');
985
    }
986
987 1
    protected function notifySmallSuccess(string $title, string $content = null, int $timeout = 4000)
988
    {
989 1
        $this->notify($title, $content, $timeout, '#739E73', 'fa fa-check', 'small');
990 1
    }
991
992 1
    protected function notifySmallDanger(string $title, string $content = null, int $timeout = 4000)
993
    {
994 1
        $this->notify($title, $content, $timeout, '#C46A69', 'fa fa-warning shake animated', 'small');
995 1
    }
996
997 1
    protected function notifySmallWarning(string $title, string $content = null, int $timeout = 4000)
998
    {
999 1
        $this->notify($title, $content, $timeout, '#C79121', 'fa fa-shield fadeInLeft animated', 'small');
1000 1
    }
1001
1002 1
    protected function notifySmallInfo(string $title, string $content = null, int $timeout = 4000)
1003
    {
1004 1
        $this->notify($title, $content, $timeout, '#3276B1', 'fa fa-bell swing animated', 'small');
1005 1
    }
1006
1007 1
    protected function notifyBigSuccess(string $title, string $content = null, int $timeout = 4000)
1008
    {
1009 1
        $this->notify($title, $content, $timeout, '#739E73', 'fa fa-check', 'big');
1010 1
    }
1011
1012 1
    protected function notifyBigDanger(string $title, string $content = null, int $timeout = 4000)
1013
    {
1014 1
        $this->notify($title, $content, $timeout, '#C46A69', 'fa fa-warning shake animated', 'big');
1015 1
    }
1016
1017 1
    protected function notifyBigWarning(string $title, string $content = null, int $timeout = 4000)
1018
    {
1019 1
        $this->notify($title, $content, $timeout, '#C79121', 'fa fa-shield fadeInLeft animated', 'big');
1020 1
    }
1021
1022 1
    protected function notifyBigInfo(string $title, string $content = null, int $timeout = 4000)
1023
    {
1024 1
        $this->notify($title, $content, $timeout, '#3276B1', 'fa fa-bell swing animated', 'big');
1025 1
    }
1026
1027
    /*
1028
    |--------------------------------------------------------------------------
1029
    | Abstract
1030
    |--------------------------------------------------------------------------
1031
    */
1032
1033
    abstract protected function init();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
1034
}
1035