Passed
Pull Request — 2.x (#1049)
by
unknown
13:20
created

Permission::groups()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
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-role',
73
                    'edit-user-groups',
74
                    'manage-modules',
75
                    'access-media-library'
76
                ];
77
                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...
78
            case Permission::SCOPE_MODULE:
79
                return array_merge(
80
                    [
81
                        'view-module',
82
                        'edit-module'
83
                    ],
84
                    (config('twill.permissions.level') === 'roleGroupModule' ? ['manage-module'] : [])
85
                );
86
                break;
87
            case Permission::SCOPE_ITEM:
88
                return [
89
                    'view-item',
90
                    'edit-item',
91
                    'manage-item'
92
                ];
93
                break;
94
        }
95
    }
96
97
    /**
98
     * Retrieve the list of modules that permissions can be applied to.
99
     *
100
     * @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...
101
     */
102
    public static function permissionableModules()
103
    {
104
        return collect(config('twill.permissions.modules', []));
105
    }
106
107
    /**
108
     * Retrieve a collection of items that belongs to keyed by permissionable module names.
109
     *
110
     * @return Collection
111
     */
112
    public static function permissionableParentModuleItems()
113
    {
114
        return self::permissionableModules()->filter(function ($module) {
115
            return !strpos($module, '.');
116
        })->mapWithKeys(function ($module) {
117
            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

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