Completed
Push — develop ( e4cc28...d114fd )
by Abdelrahman
11:17
created

AuthorizedController::authorizeResource()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 8
nc 12
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cortex\Foundation\Http\Controllers;
6
7
use ReflectionClass;
8
use ReflectionMethod;
9
use Illuminate\Support\Str;
10
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
11
12
class AuthorizedController extends AuthenticatedController
13
{
14
    use AuthorizesRequests;
15
16
    /**
17
     * The resource Ability Map.
18
     *
19
     * @var array
20
     */
21
    protected $resourceAbilityMap = [
22
        'activities' => 'audit',
23
        'index' => 'list',
24
        'logs' => 'audit',
25
    ];
26
27
    /**
28
     * The resource methods without models.
29
     *
30
     * @var array
31
     */
32
    protected $resourceMethodsWithoutModels = [];
33
34
    /**
35
     * Resource action whitelist.
36
     * Array of resource actions to skip mapping to abilities automatically.
37
     *
38
     * @var array
39
     */
40
    protected $resourceActionWhitelist = [];
41
42
    /**
43
     * Create a new authorized controller instance.
44
     *
45
     * @throws \Illuminate\Auth\Access\AuthorizationException
46
     */
47
    public function __construct()
48
    {
49
        parent::__construct();
50
51
        if (property_exists(static::class, 'resource')) {
52
            $this->authorizeResource($this->resource);
0 ignored issues
show
Bug introduced by
The property resource does not seem to exist. Did you mean resourceAbilityMap?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
53
        } else {
54
            // At this stage, sessions still not loaded yet, and `AuthorizationException`
55
            // depends on seesions to flash redirection error msg, so delegate to a middleware
56
            // Since Laravel 5.3 controller constructors executed before middleware to be able to append
57
            // new middleware to the pipeline then all middleware executed together, and sessions started in `StartSession` middleware
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 134 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
58
            $this->middleware('can:null');
59
        }
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function authorizeResource($model, $parameter = null, array $options = [], $request = null): void
66
    {
67
        $middleware = [];
68
        $parameter = $parameter ?: Str::snake(class_basename($model));
69
70
        foreach ($this->mapResourceAbilities() as $method => $ability) {
71
            $modelName = in_array($method, $this->resourceMethodsWithoutModels()) ? $model : $parameter;
72
73
            $middleware["can:{$ability},{$modelName}"][] = $method;
74
        }
75
76
        foreach ($middleware as $middlewareName => $methods) {
77
            $this->middleware($middlewareName, $options)->only($methods);
78
        }
79
    }
80
81
    /**
82
     * Map resource actions to resource abilities.
83
     *
84
     * @return array
85
     */
86
    protected function mapResourceAbilities(): array
87
    {
88
        // Reflect calling controller
89
        $controller = new ReflectionClass(static::class);
90
91
        // Get public methods and filter magic methods
92
        $methods = array_filter($controller->getMethods(ReflectionMethod::IS_PUBLIC), function ($item) use ($controller) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
93
            return $item->class === $controller->name && mb_substr($item->name, 0, 2) !== '__' && ! in_array($item->name, $this->resourceActionWhitelist);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 154 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
94
        });
95
96
        // Get controller actions
97
        $actions = array_combine($items = array_map(function ($action) {
98
            return $action->name;
99
        }, $methods), $items);
100
101
        // Map resource actions to resourse abilities
102
        array_walk($actions, function ($value, $key) use (&$actions) {
103
            $actions[$key] = array_get($this->resourceAbilityMap(), $key, $value);
104
        });
105
106
        return $actions;
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    protected function resourceAbilityMap(): array
113
    {
114
        return array_merge(parent::resourceAbilityMap(), $this->resourceAbilityMap);
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    protected function resourceMethodsWithoutModels()
121
    {
122
        return array_merge(parent::resourceMethodsWithoutModels(), $this->resourceMethodsWithoutModels);
123
    }
124
}
125