AuthorizedController   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 3
dl 0
loc 147
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 3
A authorizeResource() 0 15 5
A authorizeGeneric() 0 12 3
A mapResourceAbilities() 0 22 3
A resourceAbilityMap() 0 4 1
A resourceMethodsWithoutModels() 0 4 1
A isClassName() 0 4 1
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\Foundation\Auth\Access\AuthorizesRequests;
10
11
class AuthorizedController extends AuthenticatedController
12
{
13
    use AuthorizesRequests;
14
15
    /**
16
     * The resource Ability Map.
17
     *
18
     * @var array
19
     */
20
    protected $resourceAbilityMap = [
21
        'activities' => 'audit',
22
        'index' => 'list',
23
        'logs' => 'audit',
24
    ];
25
26
    /**
27
     * The resource methods without models.
28
     *
29
     * @var array
30
     */
31
    protected $resourceMethodsWithoutModels = [
32
        'importLogs',
33
        'import',
34
        'stash',
35
    ];
36
37
    /**
38
     * Resource action whitelist.
39
     * Array of resource actions to skip mapping to abilities automatically.
40
     *
41
     * @var array
42
     */
43
    protected $resourceActionWhitelist = [];
44
45
    /**
46
     * Create a new authorized controller instance.
47
     *
48
     * @throws \Illuminate\Auth\Access\AuthorizationException
49
     */
50
    public function __construct()
51
    {
52
        parent::__construct();
53
54
        if (property_exists(static::class, 'resource')) {
55
            $this->isClassName($this->resource) ? $this->authorizeResource($this->resource) : $this->authorizeGeneric($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...
56
        } else {
57
            // At this stage, sessions still not loaded yet, and `AuthorizationException`
58
            // depends on seesions to flash redirection error msg, so delegate to a middleware
59
            // Since Laravel 5.3 controller constructors executed before middleware to be able to append
60
            // new middleware to the pipeline then all middleware executed together, and sessions started in `StartSession` middleware
61
            $this->middleware('can:null');
62
        }
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    public function authorizeResource($model, $parameter = null, array $options = [], $request = null): void
69
    {
70
        $middleware = [];
71
        $parameter = $parameter ?: snake_case(class_basename($model));
0 ignored issues
show
Deprecated Code introduced by
The function snake_case() has been deprecated with message: Str::snake() should be used directly instead. Will be removed in Laravel 6.0.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
72
73
        foreach ($this->mapResourceAbilities() as $method => $ability) {
74
            $modelName = in_array($method, $this->resourceMethodsWithoutModels()) ? $model : $parameter;
75
76
            $middleware["can:{$ability},{$modelName}"][] = $method;
77
        }
78
79
        foreach ($middleware as $middlewareName => $methods) {
80
            $this->middleware($middlewareName, $options)->only($methods);
81
        }
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    public function authorizeGeneric($resource): void
88
    {
89
        $middleware = [];
90
91
        foreach ($this->mapResourceAbilities() as $method => $ability) {
92
            $middleware["can:{$resource}"][] = $method;
93
        }
94
95
        foreach ($middleware as $middlewareName => $methods) {
96
            $this->middleware($middlewareName)->only($methods);
97
        }
98
    }
99
100
    /**
101
     * Map resource actions to resource abilities.
102
     *
103
     * @throws \ReflectionException
104
     *
105
     * @return array
106
     */
107
    protected function mapResourceAbilities(): array
108
    {
109
        // Reflect calling controller
110
        $controller = new ReflectionClass(static::class);
111
112
        // Get public methods and filter magic methods
113
        $methods = array_filter($controller->getMethods(ReflectionMethod::IS_PUBLIC), function ($item) use ($controller) {
114
            return $item->class === $controller->name && mb_substr($item->name, 0, 2) !== '__' && ! in_array($item->name, $this->resourceActionWhitelist);
115
        });
116
117
        // Get controller actions
118
        $actions = array_combine($items = array_map(function ($action) {
119
            return $action->name;
120
        }, $methods), $items);
121
122
        // Map resource actions to resourse abilities
123
        array_walk($actions, function ($value, $key) use (&$actions) {
124
            $actions[$key] = array_get($this->resourceAbilityMap(), $key, $value);
0 ignored issues
show
Deprecated Code introduced by
The function array_get() has been deprecated with message: Arr::get() should be used directly instead. Will be removed in Laravel 6.0.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
125
        });
126
127
        return $actions;
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133
    protected function resourceAbilityMap(): array
134
    {
135
        return array_merge(parent::resourceAbilityMap(), $this->resourceAbilityMap);
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    protected function resourceMethodsWithoutModels()
142
    {
143
        return array_merge(parent::resourceMethodsWithoutModels(), $this->resourceMethodsWithoutModels);
144
    }
145
146
    /**
147
     * Checks if the given string looks like a fully qualified class name.
148
     *
149
     * @param string $value
150
     *
151
     * @return bool
152
     */
153
    protected function isClassName($value)
154
    {
155
        return mb_strpos($value, '\\') !== false;
156
    }
157
}
158