Completed
Push — master ( 6c23f8...af8e08 )
by Abdelrahman
07:57
created

HasRoles::hydrateIfString()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 3
nc 6
nop 1
dl 0
loc 5
rs 9.2
c 1
b 0
f 0
1
<?php
2
3
/*
4
 * NOTICE OF LICENSE
5
 *
6
 * Part of the Rinvex Fort Package.
7
 *
8
 * This source file is subject to The MIT License (MIT)
9
 * that is bundled with this package in the LICENSE file.
10
 *
11
 * Package: Rinvex Fort Package
12
 * License: The MIT License (MIT)
13
 * Link:    https://rinvex.com
14
 */
15
16
namespace Rinvex\Fort\Traits;
17
18
use Rinvex\Fort\Models\Role;
19
use Illuminate\Support\Collection;
20
21
trait HasRoles
22
{
23
    use HasAbilities;
24
25
    /**
26
     * Assign the given role(s) to the entity.
27
     *
28
     * @param mixed $roles
29
     *
30
     * @return $this
31
     */
32
    public function assignRoles($roles)
33
    {
34
        // Array of role slugs
35
        $roles = $this->hydrateIfString($roles);
36
37
        // Single role model
38
        if ($roles instanceof Role) {
39
            $roles = [$roles->id];
40
        }
41
42
        // Fire the role assigning event
43
        static::$dispatcher->fire('rinvex.fort.role.assigning', [$this, $roles]);
44
45
        // Assign roles
46
        $this->roles()->syncWithoutDetaching($roles);
0 ignored issues
show
Bug introduced by
It seems like roles() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
47
48
        // Fire the role assigned event
49
        static::$dispatcher->fire('rinvex.fort.role.assigned', [$this, $roles]);
50
51
        return $this;
52
    }
53
54
    /**
55
     * Sync the given role(s) to the entity.
56
     *
57
     * @param mixed $roles
58
     *
59
     * @return $this
60
     */
61
    public function syncRoles($roles)
62
    {
63
        // Array of role slugs
64
        $roles = $this->hydrateIfString($roles);
65
66
        // Single role model
67
        if ($roles instanceof Role) {
68
            $roles = [$roles->id];
69
        }
70
71
        // Fire the role syncing event
72
        static::$dispatcher->fire('rinvex.fort.role.syncing', [$this, $roles]);
73
74
        // Assign roles
75
        $this->roles()->sync($roles);
0 ignored issues
show
Bug introduced by
It seems like roles() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
76
77
        // Fire the role synced event
78
        static::$dispatcher->fire('rinvex.fort.role.synced', [$this, $roles]);
79
80
        return $this;
81
    }
82
83
    /**
84
     * Remove the given role(s) from the entity.
85
     *
86
     * @param mixed $roles
87
     *
88
     * @return $this
89
     */
90
    public function removeRoles($roles)
91
    {
92
        // Array of role slugs
93
        $roles = $this->hydrateIfString($roles);
94
95
        // Fire the role removed event
96
        static::$dispatcher->fire('rinvex.fort.role.removing', [$this, $roles]);
97
98
        // Detach roles
99
        $this->roles()->detach($roles);
0 ignored issues
show
Bug introduced by
It seems like roles() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
100
101
        // Fire the role removed event
102
        static::$dispatcher->fire('rinvex.fort.role.removed', [$this, $roles]);
103
104
        return $this;
105
    }
106
107
    /**
108
     * Determine if the entity has (one of) the given roles.
109
     *
110
     * @param mixed $roles
111
     *
112
     * @return bool
113
     */
114
    public function hasRole($roles)
115
    {
116
        // Single role slug
117
        if (is_string($roles)) {
118
            return $this->roles->contains('slug', $roles);
0 ignored issues
show
Bug introduced by
The property roles does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
119
        }
120
121
        // Single role model
122
        if ($roles instanceof Role) {
123
            return $this->roles->contains('slug', $roles->slug);
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<Rinvex\Fort\Models\Role>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
124
        }
125
126
        // Array of role slugs
127
        if (is_array($roles) && is_string($roles[0])) {
128
            return $this->roles->pluck('slug')->intersect($roles)->isEmpty();
129
        }
130
131
        // Array of role Ids
132
        if (is_array($roles) && is_int($roles[0])) {
133
            return $this->roles->pluck('id')->intersect($roles)->isEmpty();
134
        }
135
136
        // Collection of role models
137
        if ($roles instanceof Collection) {
138
            return ! $roles->intersect($this->roles->pluck('slug'))->isEmpty();
139
        }
140
141
        return false;
142
    }
143
144
    /**
145
     * Alias for `hasRole` method.
146
     *
147
     * @param mixed $roles
148
     *
149
     * @return bool
150
     */
151
    public function hasAnyRole($roles)
152
    {
153
        return $this->hasRole($roles);
154
    }
155
156
    /**
157
     * Determine if the given entity has all of the given roles.
158
     *
159
     * @param mixed $roles
160
     *
161
     * @return bool
162
     */
163
    public function hasAllRoles($roles)
164
    {
165
        // Single role slug
166
        if (is_string($roles)) {
167
            return $this->roles->contains('slug', $roles);
168
        }
169
170
        // Single role model
171
        if ($roles instanceof Role) {
172
            return $this->roles->contains('slug', $roles->slug);
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<Rinvex\Fort\Models\Role>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
173
        }
174
175
        // Array of role slugs OR Collection of role models
176
        if ($roles instanceof Collection || (is_array($roles) && is_string($roles[0]))) {
177
            return $this->roles->pluck('slug')->count() == count($roles)
178
                   && $this->roles->pluck('slug')->diff($roles)->isEmpty();
179
        }
180
181
        return $this->roles->pluck('id')->count() == count($roles)
182
               && $this->roles->pluck('id')->diff($roles)->isEmpty();
183
    }
184
185
    /**
186
     * Hydrate roles if it's string based.
187
     *
188
     * @param $roles
189
     *
190
     * @return array
191
     */
192
    protected function hydrateIfString($roles)
193
    {
194
        return is_string($roles) || (is_array($roles) && is_string($roles[0]))
195
            ? Role::whereIn('slug', (array) $roles)->get() : $roles;
196
    }
197
}
198