Completed
Push — master ( 425779...b6e961 )
by Abdelrahman
08:30
created

Ability::setRolesAttribute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Rinvex\Fort\Models;
6
7
use Watson\Validating\ValidatingTrait;
8
use Illuminate\Database\Eloquent\Model;
9
use Rinvex\Cacheable\CacheableEloquent;
10
use Spatie\Translatable\HasTranslations;
11
12
/**
13
 * Rinvex\Fort\Models\Ability.
14
 *
15
 * @property int                                                                      $id
16
 * @property string                                                                   $action
17
 * @property string                                                                   $resource
18
 * @property string|null                                                              $policy
19
 * @property array                                                                    $name
20
 * @property array                                                                    $description
21
 * @property \Carbon\Carbon|null                                                      $created_at
22
 * @property \Carbon\Carbon|null                                                      $updated_at
23
 * @property \Carbon\Carbon|null                                                      $deleted_at
24
 * @property-read string                                                              $slug
25
 * @property \Illuminate\Database\Eloquent\Collection|\Rinvex\Fort\Models\Role[]      $roles
26
 * @property-read \Illuminate\Database\Eloquent\Collection|\Rinvex\Fort\Models\User[] $users
27
 *
28
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Fort\Models\Ability whereAction($value)
29
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Fort\Models\Ability whereCreatedAt($value)
30
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Fort\Models\Ability whereDeletedAt($value)
31
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Fort\Models\Ability whereDescription($value)
32
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Fort\Models\Ability whereId($value)
33
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Fort\Models\Ability whereName($value)
34
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Fort\Models\Ability wherePolicy($value)
35
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Fort\Models\Ability whereResource($value)
36
 * @method static \Illuminate\Database\Eloquent\Builder|\Rinvex\Fort\Models\Ability whereUpdatedAt($value)
37
 * @mixin \Eloquent
38
 */
39
class Ability extends Model
40
{
41
    use HasTranslations;
42
    use ValidatingTrait;
43
    use CacheableEloquent;
44
45
    /**
46
     * {@inheritdoc}
47
     */
48
    protected $dates = [
49
        'deleted_at',
50
    ];
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    protected $fillable = [
56
        'action',
57
        'resource',
58
        'policy',
59
        'name',
60
        'description',
61
        'roles',
62
    ];
63
64
    /**
65
     * {@inheritdoc}
66
     */
67
    protected $observables = [
68
        'attaching',
69
        'attached',
70
        'detaching',
71
        'detached',
72
        'validating',
73
        'validated',
74
    ];
75
76
    /**
77
     * The attributes that are translatable.
78
     *
79
     * @var array
80
     */
81
    public $translatable = [
82
        'name',
83
        'description',
84
    ];
85
86
    /**
87
     * The default rules that the model will validate against.
88
     *
89
     * @var array
90
     */
91
    protected $rules = [];
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    protected $validationMessages = [
97
        'action.unique' => 'The combination of (action & resource) fields has already been taken.',
98
        'resource.unique' => 'The combination of (action & resource) fields has already been taken.',
99
    ];
100
101
    /**
102
     * Whether the model should throw a
103
     * ValidationException if it fails validation.
104
     *
105
     * @var bool
106
     */
107
    protected $throwValidationExceptions = true;
108
109
    /**
110
     * Create a new Eloquent model instance.
111
     *
112
     * @param array $attributes
113
     */
114
    public function __construct(array $attributes = [])
115
    {
116
        parent::__construct($attributes);
117
118
        $this->setTable(config('rinvex.fort.tables.abilities'));
119
        $this->setRules([
120
            'name' => 'required|string|max:150',
121
            'action' => 'required|unique:'.config('rinvex.fort.tables.abilities').',action,NULL,id,resource,'.($this->resource ?? 'null'),
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 138 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...
122
            'resource' => 'required|unique:'.config('rinvex.fort.tables.abilities').',resource,NULL,id,action,'.($this->action ?? 'null'),
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 138 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...
123
        ]);
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    protected static function boot()
130
    {
131
        parent::boot();
132
133
        static::updated(function (self $ability) {
0 ignored issues
show
Unused Code introduced by
The parameter $ability is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
134
            Role::forgetCache();
135
            User::forgetCache();
136
        });
137
138
        static::deleted(function (self $ability) {
0 ignored issues
show
Unused Code introduced by
The parameter $ability is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
139
            Role::forgetCache();
140
            User::forgetCache();
141
        });
142
143
        static::attached(function (self $ability) {
0 ignored issues
show
Unused Code introduced by
The parameter $ability is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
144
            Role::forgetCache();
145
            User::forgetCache();
146
        });
147
148
        static::detached(function (self $ability) {
0 ignored issues
show
Unused Code introduced by
The parameter $ability is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
149
            Role::forgetCache();
150
            User::forgetCache();
151
        });
152
    }
153
154
    /**
155
     * Register an attaching ability event with the dispatcher.
156
     *
157
     * @param \Closure|string $callback
158
     *
159
     * @return void
160
     */
161
    public static function attaching($callback)
162
    {
163
        static::registerModelEvent('attaching', $callback);
164
    }
165
166
    /**
167
     * Register an attached ability event with the dispatcher.
168
     *
169
     * @param \Closure|string $callback
170
     *
171
     * @return void
172
     */
173
    public static function attached($callback)
174
    {
175
        static::registerModelEvent('attached', $callback);
176
    }
177
178
    /**
179
     * Register a detaching ability event with the dispatcher.
180
     *
181
     * @param \Closure|string $callback
182
     *
183
     * @return void
184
     */
185
    public static function detaching($callback)
186
    {
187
        static::registerModelEvent('detaching', $callback);
188
    }
189
190
    /**
191
     * Register a detached ability event with the dispatcher.
192
     *
193
     * @param \Closure|string $callback
194
     *
195
     * @return void
196
     */
197
    public static function detached($callback)
198
    {
199
        static::registerModelEvent('detached', $callback);
200
    }
201
202
    /**
203
     * Register a validating ability event with the dispatcher.
204
     *
205
     * @param \Closure|string $callback
206
     *
207
     * @return void
208
     */
209
    public static function validating($callback)
210
    {
211
        static::registerModelEvent('validating', $callback);
212
    }
213
214
    /**
215
     * Register a validated ability event with the dispatcher.
216
     *
217
     * @param \Closure|string $callback
218
     *
219
     * @return void
220
     */
221
    public static function validated($callback)
222
    {
223
        static::registerModelEvent('validated', $callback);
224
    }
225
226
    /**
227
     * An ability can be applied to roles.
228
     *
229
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
230
     */
231
    public function roles()
232
    {
233
        return $this->belongsToMany(config('rinvex.fort.models.role'), config('rinvex.fort.tables.ability_role'), 'ability_id', 'role_id')
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 138 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...
234
                    ->withTimestamps();
235
    }
236
237
    /**
238
     * An ability can be applied to users.
239
     *
240
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
241
     */
242
    public function users()
243
    {
244
        $userModel = config('auth.providers.'.config('auth.guards.'.config('auth.defaults.guard').'.provider').'.model');
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 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...
245
246
        return $this->belongsToMany($userModel, config('rinvex.fort.tables.ability_user'), 'ability_id', 'user_id')
247
                    ->withTimestamps();
248
    }
249
250
    /**
251
     * Set the translatable name attribute.
252
     *
253
     * @param string $value
254
     *
255
     * @return void
256
     */
257
    public function setNameAttribute($value)
258
    {
259
        $this->attributes['name'] = json_encode(! is_array($value) ? [app()->getLocale() => $value] : $value);
260
    }
261
262
    /**
263
     * Set the translatable description attribute.
264
     *
265
     * @param string $value
266
     *
267
     * @return void
268
     */
269
    public function setDescriptionAttribute($value)
270
    {
271
        $this->attributes['description'] = ! empty($value) ? json_encode(! is_array($value) ? [app()->getLocale() => $value] : $value) : null;
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 142 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...
272
    }
273
274
    /**
275
     * Determine if the ability is super admin.
276
     *
277
     * @return bool
278
     */
279
    public function isSuperadmin()
280
    {
281
        return ! $this->policy && $this->resource === 'global' && $this->action === 'superadmin';
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->policy of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
282
    }
283
284
    /**
285
     * Determine if the ability is protected.
286
     *
287
     * @return bool
288
     */
289
    public function isProtected()
290
    {
291
        return in_array($this->id, config('rinvex.fort.protected.abilities'));
292
    }
293
294
    /**
295
     * Get slug attribute out of ability's action & resource.
296
     *
297
     * @return string
298
     */
299
    public function getSlugAttribute()
300
    {
301
        return $this->action.'-'.$this->resource;
302
    }
303
304
    /**
305
     * Prepare a unique rule, adding the table name, column and model indetifier
306
     * if required.
307
     *
308
     * @param array  $parameters
309
     * @param string $field
310
     *
311
     * @return string
312
     */
313
    protected function prepareUniqueRule($parameters, $field)
314
    {
315
        // If the table name isn't set, infer it.
316
        if (empty($parameters[0])) {
317
            $parameters[0] = $this->getModel()->getTable();
318
        }
319
320
        // If the connection name isn't set but exists, infer it.
321
        if ((mb_strpos($parameters[0], '.') === false) && (($connectionName = $this->getModel()->getConnectionName()) !== null)) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 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...
322
            $parameters[0] = $connectionName.'.'.$parameters[0];
323
        }
324
325
        // If the field name isn't get, infer it.
326
        if (! isset($parameters[1])) {
327
            $parameters[1] = $field;
328
        }
329
330
        if ($this->exists) {
331
            // If the identifier isn't set, infer it.
332
            if (! isset($parameters[2]) || mb_strtolower($parameters[2]) === 'null') {
333
                $parameters[2] = $this->getModel()->getKey();
334
            }
335
336
            // If the primary key isn't set, infer it.
337
            if (! isset($parameters[3])) {
338
                $parameters[3] = $this->getModel()->getKeyName();
339
            }
340
341
            // If the additional where clause isn't set, infer it.
342
            // Example: unique:abilities,resource,123,id,action,NULL
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
343
            foreach ($parameters as $key => $parameter) {
344
                if (mb_strtolower((string) $parameter) === 'null') {
345
                    $parameters[$key] = $this->getModel()->{$parameters[$key - 1]};
346
                }
347
            }
348
        }
349
350
        return 'unique:'.implode(',', $parameters);
351
    }
352
353
    /**
354
     * Attach the ability roles.
355
     *
356
     * @param mixed $roles
357
     *
358
     * @return void
359
     */
360
    public function setRolesAttribute($roles)
361
    {
362
        static::saved(function (self $model) use ($roles) {
363
            $model->roles()->sync($roles);
364
        });
365
    }
366
}
367