Passed
Push — feature/permissions-management ( 41e93d )
by
unknown
11:22 queued 04:04
created

Permission::available()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 30
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 23
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 30
rs 9.2408
1
<?php
2
3
namespace A17\Twill\Models;
4
5
use Illuminate\Support\Str;
6
use Illuminate\Foundation\Auth\User;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, A17\Twill\Models\User. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use Illuminate\Database\Eloquent\Builder;
8
use Illuminate\Database\Eloquent\Relations\MorphTo;
9
use Illuminate\Database\Eloquent\Model as BaseModel;
10
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
11
12
/**
13
 * Permission model
14
 *
15
 * @property-read string $permissionableModule
16
 * @method static Builder global() Get global scope permissions.
17
 * @method static Builder module() Get module scope permissions.
18
 * @method static Builder moduleItem() Get module item scope permissions.
19
 * @method static Builder ofItem(BaseModel $item) Get permissions related to an item.
20
 * @method static Builder ofModuleName(string $moduleName) Get permissions related to a Twill module.
21
 * @method static Builder ofModel(BaseModel $model) Get permissions related to a model.
22
 */
23
class Permission extends BaseModel
24
{
25
    /**
26
     * Constant that represents a list of permissions that belongs to the global scope.
27
     *
28
     * @var string
29
     * @see Permission::available($scope)
30
     */
31
    const SCOPE_GLOBAL = 'global';
32
33
    /**
34
     * Constant that represents a list of permissions that belongs to the module scope.
35
     *
36
     * @var string
37
     * @see Permission::available($scope)
38
     */
39
    const SCOPE_MODULE = 'module';
40
41
    /**
42
     * Constant that represents a list of permissions that belongs to the module item scope.
43
     *
44
     * @var string
45
     * @see Permission::available($scope)
46
     */
47
    const SCOPE_ITEM = 'item';
48
49
    protected $fillable = [
50
        'name',
51
        'permissionable_type',
52
        'permissionable_id',
53
        'is_default'
54
    ];
55
56
    protected $appends = ['permissionable_module'];
57
58
    /**
59
     * Return an array of permission names that belongs to
60
     * a certain scope (global, module or item).
61
     *
62
     * @param string $scope
63
     * @return string[]|void
64
     */
65
    public static function available($scope)
66
    {
67
        switch ($scope) {
68
            case Permission::SCOPE_GLOBAL:
69
                return [
70
                    'edit-settings',
71
                    'edit-users',
72
                    'edit-user-roles',
73
                    'edit-user-groups',
74
                    'manage-modules',
75
                    'access-media-library',
76
                    'edit-media-library'
77
                ];
78
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
79
            case Permission::SCOPE_MODULE:
80
                return array_merge(
81
                    [
82
                        'view-module',
83
                        'edit-module'
84
                    ],
85
                    (config('twill.permissions.level') === 'roleGroupItem' ? ['manage-module'] : [])
86
                );
87
                break;
88
            case Permission::SCOPE_ITEM:
89
                return [
90
                    'view-item',
91
                    'edit-item',
92
                    'manage-item'
93
                ];
94
                break;
95
        }
96
    }
97
98
    /**
99
     * Retrieve the list of modules that permissions can be applied to.
100
     *
101
     * @return Collection
0 ignored issues
show
Bug introduced by
The type A17\Twill\Models\Collection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
102
     */
103
    public static function permissionableModules()
104
    {
105
        return collect(config('twill.permissions.modules', []));
106
    }
107
108
    /**
109
     * Retrieve a collection of items that belongs to keyed by permissionable module names.
110
     *
111
     * @return Collection
112
     */
113
    public static function permissionableParentModuleItems()
114
    {
115
        return self::permissionableModules()->filter(function ($module) {
116
            return !strpos($module, '.');
117
        })->mapWithKeys(function ($module) {
118
            return [$module => getRepositoryByModuleName($module)->get([], [], [], -1)];
0 ignored issues
show
Unused Code introduced by
The call to Illuminate\Container\Container::get() has too many arguments starting with array(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
            return [$module => getRepositoryByModuleName($module)->/** @scrutinizer ignore-call */ get([], [], [], -1)];

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
119
        });
120
    }
121
122
    /**
123
     * Get the parent permissionable model (one of the permissionale module).
124
     *
125
     * @return MorphTo|Collection|User[]
126
     */
127
    public function permissionable()
128
    {
129
        return $this->morphTo();
130
    }
131
132
    /**
133
     * User model relationship
134
     *
135
     * @return BelongsToMany|Collection|User[]
136
     */
137
    public function users()
138
    {
139
        return $this->belongsToMany(twillModel('user'), 'permission_twill_user', 'permission_id', 'twill_user_id');
140
    }
141
142
    /**
143
     * Role model relationship
144
     *
145
     * @return BelongsToMany|Collection|BaseModel[]
146
     */
147
    public function roles()
148
    {
149
        return $this->belongsToMany(twillModel('role'), 'permission_role', 'permission_id', 'role_id');
150
    }
151
152
    /**
153
     * Group model relationship
154
     *
155
     * @return BelongsToMany|Collection|BaseModel[]
156
     */
157
    public function groups()
158
    {
159
        return $this->belongsToMany(twillModel('group'), 'group_permission', 'permission_id', 'group_id');
160
    }
161
162
    /**
163
     * Scope a query to only include global scope permissions.
164
     *
165
     * @param Builder $query
166
     * @return Builder
167
     */
168
    public function scopeGlobal(Builder $query)
169
    {
170
        return $query->whereNull('permissionable_type')->whereNull('permissionable_id');
171
    }
172
173
    /**
174
     * Scope a query to only include module scope permissions.
175
     *
176
     * @param Builder $query
177
     * @return Builder
178
     */
179
    public function scopeModule(Builder $query)
180
    {
181
        return $query->whereNotNull('permissionable_type')->whereNull('permissionable_id');
182
    }
183
184
    /**
185
     * Scope a query to only include module item scope permissions.
186
     *
187
     * @param Builder $query
188
     * @return Builder
189
     */
190
    public function scopeModuleItem(Builder $query)
191
    {
192
        return $query->whereNotNull('permissionable_type')->whereNotNull('permissionable_id');
193
    }
194
195
    /**
196
     * Scope a query to only include permissions related to an item.
197
     *
198
     * @param Builder $query
199
     * @param BaseModel $item
200
     * @return Builder
201
     */
202
    public function scopeOfItem(Builder $query, BaseModel $item)
203
    {
204
        $permissionableSubmodule = self::permissionableModules()->filter(function($module) use ($item){
205
            return strpos($module, '.') && explode('.', $module)[1] === getModuleNameByModel($item);
206
        })->first();
207
208
        if ($permissionableSubmodule) {
209
            $parentRelation = isset($item->parentRelation) ? $item->parentRelation : Str::singular(explode('.', $permissionableSubmodule)[0]);
210
            $item = $item->$parentRelation;
211
        }
212
213
        return $query->where([
214
            ['permissionable_type', get_class($item)],
215
            ['permissionable_id', $item->id],
216
        ]);
217
    }
218
219
    /**
220
     * Scope a query to only include permissions related to a Twill module.
221
     *
222
     * @param Builder $query
223
     * @param string $moduleName
224
     * @return Builder
225
     */
226
    public function scopeOfModuleName(Builder $query, $moduleName)
227
    {
228
        // Submodule's permission will inherit from parent module
229
        if (strpos($moduleName, '.')) {
230
            $moduleName = explode('.', $moduleName)[0];
231
        }
232
        return $query->ofModel(getModelByModuleName($moduleName));
233
    }
234
235
    /**
236
     * Scope a query to only include permissions related to a model.
237
     *
238
     * @param Builder $query
239
     * @param string $model
240
     * @return Builder
241
     */
242
    public function scopeOfModel(Builder $query, $model)
243
    {
244
        return $query->where('permissionable_type', $model);
245
    }
246
247
    /**
248
     * Get the permissionable module type of current permission
249
     *
250
     * @return string
251
     */
252
    public function getPermissionableModuleAttribute()
253
    {
254
        return getModuleNameByModel($this->permissionable_type);
255
    }
256
257
}
258