Completed
Push — master ( 19b92d...15c8d0 )
by vistart
04:37
created

RegistrationTrait::getAuthManager()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 9.4285
cc 2
eloc 3
nc 2
nop 0
crap 2
1
<?php
2
3
/**
4
 *  _   __ __ _____ _____ ___  ____  _____
5
 * | | / // // ___//_  _//   ||  __||_   _|
6
 * | |/ // /(__  )  / / / /| || |     | |
7
 * |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link https://vistart.me/
9
 * @copyright Copyright (c) 2016 - 2017 vistart
10
 * @license https://vistart.me/license/
11
 */
12
13
namespace rhosocial\base\models\traits;
14
15
use Yii;
16
use yii\base\ModelEvent;
17
use yii\db\Exception;
18
use yii\db\IntegrityException;
19
use yii\rbac\BaseManager;
20
use yii\rbac\Role;
21
22
/**
23
 * User features concerning registration.
24
 *
25
 * @property-read mixed $authManager
26
 * @property mixed $source
27
 * @property array $sourceRules rules associated with source attribute.
28
 * @version 1.0
29
 * @author vistart <[email protected]>
30
 */
31
trait RegistrationTrait
32
{
33
34
    /**
35
     * @event Event an event that is triggered after user is registered successfully.
36
     */
37
    public static $eventAfterRegister = "afterRegister";
38
39
    /**
40
     * @event Event an event that is triggered before registration.
41
     */
42
    public static $eventBeforeRegister = "beforeRegister";
43
44
    /**
45
     * @event Event an event that is triggered when registration failed.
46
     */
47
    public static $eventRegisterFailed = "registerFailed";
48
49
    /**
50
     * @event Event an event that is triggered after user is deregistered successfully.
51
     */
52
    public static $eventAfterDeregister = "afterDeregister";
53
54
    /**
55
     * @event Event an event that is triggered before deregistration.
56
     */
57
    public static $eventBeforeDeregister = "beforeDeregister";
58
59
    /**
60
     * @event Event an event that is triggered when deregistration failed.
61
     */
62
    public static $eventDeregisterFailed = "deregisterFailed";
63
64
    /**
65
     * @var string name of attribute which store the source. if you don't want to
66
     * record source, please assign false.
67
     */
68
    public $sourceAttribute = 'source';
69
    private $_sourceRules = [];
70
    public static $sourceSelf = '0';
71
72
    /**
73
     * @var string auth manager component id.
74
     */
75
    public $authManagerId = 'authManager';
76
77
    /**
78
     * Get auth manager. If auth manager not configured, Yii::$app->authManager
79
     * will be given.
80
     * @return BaseManager
81
     */
82 109
    public function getAuthManager()
83
    {
84 109
        $authManagerId = $this->authManagerId;
85 109
        return empty($authManagerId) ? Yii::$app->authManager : Yii::$app->$authManagerId;
86
    }
87
88
    /**
89
     * Register new user.
90
     * It is equivalent to store the current user and its associated models into
91
     * database synchronously. The registration will be terminated immediately
92
     * if any errors occur in the process, and all the earlier steps succeeded
93
     * are rolled back.
94
     * If auth manager configured, and auth role(s) provided, it(they) will be
95
     * assigned to user after registration.
96
     * If current user is not a new one(isNewRecord = false), the registration
97
     * will be skipped and return false.
98
     * The $eventBeforeRegister will be triggered before registration starts.
99
     * If registration finished, the $eventAfterRegister will be triggered. or
100
     * $eventRegisterFailed will be triggered when any errors occured.
101
     * @param array $associatedModels The models associated with user to be stored synchronously.
102
     * @param string|array $authRoles auth name, auth instance, auth name array or auth instance array.
103
     * @return boolean Whether the registration succeeds or not.
104
     * @throws IntegrityException when inserting user and associated models failed.
105
     */
106 110
    public function register($associatedModels = [], $authRoles = [])
107
    {
108 110
        if (!$this->getIsNewRecord()) {
0 ignored issues
show
Bug introduced by
It seems like getIsNewRecord() 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...
109 3
            return false;
110
        }
111 110
        $this->trigger(static::$eventBeforeRegister);
0 ignored issues
show
Bug introduced by
It seems like trigger() 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...
112 110
        $transaction = $this->getDb()->beginTransaction();
0 ignored issues
show
Bug introduced by
It seems like getDb() 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...
113
        try {
114 110
            if (!$this->save()) {
0 ignored issues
show
Bug introduced by
It seems like save() 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...
115 1
                throw new IntegrityException('Registration Error(s) Occured: User Save Failed.', $this->getErrors());
0 ignored issues
show
Bug introduced by
It seems like getErrors() 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...
116
            }
117 109
            if ($authManager = $this->getAuthManager() && !empty($authRoles)) {
118
                if (is_string($authRoles) || $authRoles instanceof Role || !is_array($authRoles)) {
119
                    $authRoles = [$authRoles];
120
                }
121
                foreach ($authRoles as $role) {
122
                    if (is_string($role)) {
123
                        $role = $authManager->getRole($role);
0 ignored issues
show
Bug introduced by
The method getRole cannot be called on $authManager (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
124
                    }
125
                    if ($role instanceof Role) {
126
                        $authManager->assign($role, $this->getGUID());
0 ignored issues
show
Bug introduced by
It seems like getGUID() 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...
Bug introduced by
The method assign cannot be called on $authManager (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
127
                    }
128
                }
129
            }
130 109
            if (!empty($associatedModels) && is_array($associatedModels)) {
131 36
                foreach ($associatedModels as $model) {
132 36
                    if (!$model->save()) {
133 36
                        throw new IntegrityException('Registration Error(s) Occured: Associated Models Save Failed.', $model->getErrors());
134
                    }
135
                }
136
            }
137 109
            $transaction->commit();
138 1
        } catch (\Exception $ex) {
139 1
            $transaction->rollBack();
140 1
            $this->trigger(static::$eventRegisterFailed);
0 ignored issues
show
Bug introduced by
It seems like trigger() 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...
141 1
            if (YII_DEBUG || YII_ENV !== YII_ENV_PROD) {
142 1
                Yii::error($ex->getMessage(), static::class . '\register');
143 1
                return $ex;
144
            }
145
            Yii::warning($ex->getMessage(), static::class . '\register');
146
            return false;
147
        }
148 109
        $this->trigger(static::$eventAfterRegister);
0 ignored issues
show
Bug introduced by
It seems like trigger() 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...
149 109
        return true;
150
    }
151
152
    /**
153
     * Deregister current user itself.
154
     * It is equivalent to delete current user and its associated models. BUT it
155
     * deletes current user ONLY, the associated models will not be deleted
156
     * forwardly. So you should set the foreign key of associated models' table
157
     * referenced from primary key of user table, and their association mode is
158
     * 'on update cascade' and 'on delete cascade'.
159
     * the $eventBeforeDeregister will be triggered before deregistration starts.
160
     * if deregistration finished, the $eventAfterDeregister will be triggered. or
161
     * $eventDeregisterFailed will be triggered when any errors occured.
162
     * @return boolean Whether deregistration succeeds or not.
163
     * @throws IntegrityException when deleting user failed.
164
     */
165 109
    public function deregister()
166
    {
167 109
        if ($this->getIsNewRecord()) {
0 ignored issues
show
Bug introduced by
It seems like getIsNewRecord() 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...
168 7
            return false;
169
        }
170 108
        $this->trigger(static::$eventBeforeDeregister);
0 ignored issues
show
Bug introduced by
It seems like trigger() 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...
171 108
        $transaction = $this->getDb()->beginTransaction();
0 ignored issues
show
Bug introduced by
It seems like getDb() 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...
172
        try {
173 108
            $result = $this->delete();
0 ignored issues
show
Bug introduced by
It seems like delete() 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...
174 108
            if ($result != 1) {
175
                throw new IntegrityException('Deregistration Error(s) Occured.', $this->getErrors());
0 ignored issues
show
Bug introduced by
It seems like getErrors() 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...
176
            }
177 108
            $transaction->commit();
178
        } catch (\Exception $ex) {
179
            $transaction->rollBack();
180
            $this->trigger(static::$eventDeregisterFailed);
0 ignored issues
show
Bug introduced by
It seems like trigger() 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...
181
            if (YII_DEBUG || YII_ENV !== YII_ENV_PROD) {
182
                Yii::error($ex->getMessage(), static::class . '\deregister');
183
                return $ex;
184
            }
185
            Yii::warning($ex->getMessage(), static::class . '\deregister');
186
            return false;
187
        }
188 108
        $this->trigger(static::$eventAfterDeregister);
0 ignored issues
show
Bug introduced by
It seems like trigger() 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...
189 108
        return $result == 1;
190
    }
191
192
    /**
193
     * Get source.
194
     * @return string
195
     */
196 1
    public function getSource()
197
    {
198 1
        $sourceAttribute = $this->sourceAttribute;
199 1
        return is_string($sourceAttribute) ? $this->$sourceAttribute : null;
200
    }
201
202
    /**
203
     * Set source.
204
     * @param string $source
205
     */
206 2
    public function setSource($source)
207
    {
208 2
        $sourceAttribute = $this->sourceAttribute;
209 2
        return is_string($sourceAttribute) ? $this->$sourceAttribute = $source : null;
210
    }
211
212
    /**
213
     * Get the rules associated with source attribute.
214
     * @return array rules.
215
     */
216 120
    public function getSourceRules()
217
    {
218 120
        if (empty($this->_sourceRules)) {
219 119
            $this->_sourceRules = [
220 119
                [[$this->sourceAttribute], 'required'],
221 119
                [[$this->sourceAttribute], 'string'],
222
            ];
223
        }
224 120
        return $this->_sourceRules;
225
    }
226
227
    /**
228
     * Set the rules associated with source attribute.
229
     * @param array $rules
230
     */
231 1
    public function setSourceRules($rules)
232
    {
233 1
        if (!empty($rules) && is_array($rules)) {
234 1
            $this->_sourceRules = $rules;
235
        }
236 1
    }
237
238
    /**
239
     * Initialize the source attribute with $sourceSelf.
240
     * This method is ONLY used for being triggered by event. DO NOT call,
241
     * override or modify it directly, unless you know the consequences.
242
     * @param ModelEvent $event
243
     */
244 126
    public function onInitSourceAttribute($event)
245
    {
246 126
        $sender = $event->sender;
247 126
        $sourceAttribute = $sender->sourceAttribute;
248 126
        $sender->$sourceAttribute = static::$sourceSelf;
249 126
    }
250
}
251