Completed
Push — master ( bf148f...113cf9 )
by vistart
07:06
created

RegistrationTrait::setSource()   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
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 1
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 144
    public function getAuthManager()
83
    {
84 144
        $authManagerId = $this->authManagerId;
85 144
        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 145
    public function register($associatedModels = [], $authRoles = [])
107
    {
108 145
        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 145
        $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 145
        $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 145
            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 144
            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 144
            if (!empty($associatedModels) && is_array($associatedModels)) {
131 54
                foreach ($associatedModels as $model) {
132 54
                    if (!$model->save()) {
133 54
                        throw new IntegrityException('Registration Error(s) Occured: Associated Models Save Failed.', $model->getErrors());
134
                    }
135
                }
136
            }
137 144
            $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 144
        $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 144
        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 161
    public function deregister()
166
    {
167 161
        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 146
            return false;
169
        }
170 145
        $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 145
        $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 145
            $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 145
            if ($result == 0) {
175 1
                throw new IntegrityException('User has not existed.');
176
            }
177 145
            if ($result != 1) {
178
                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...
179
            }
180 145
            $transaction->commit();
181 1
        } catch (\Exception $ex) {
182 1
            $transaction->rollBack();
183 1
            $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...
184 1
            if (YII_DEBUG || YII_ENV !== YII_ENV_PROD) {
185 1
                Yii::error($ex->getMessage(), static::class . '\deregister');
186 1
                return $ex;
187
            }
188
            Yii::warning($ex->getMessage(), static::class . '\deregister');
189
            return false;
190
        }
191 145
        $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...
192 145
        return $result == 1;
193
    }
194
195
    /**
196
     * Get source.
197
     * @return string
198
     */
199 1
    public function getSource()
200
    {
201 1
        $sourceAttribute = $this->sourceAttribute;
202 1
        return is_string($sourceAttribute) ? $this->$sourceAttribute : null;
203
    }
204
205
    /**
206
     * Set source.
207
     * @param string $source
208
     */
209 2
    public function setSource($source)
210
    {
211 2
        $sourceAttribute = $this->sourceAttribute;
212 2
        return is_string($sourceAttribute) ? $this->$sourceAttribute = $source : null;
213
    }
214
215
    /**
216
     * Get the rules associated with source attribute.
217
     * @return array rules.
218
     */
219 155
    public function getSourceRules()
220
    {
221 155
        if (empty($this->_sourceRules)) {
222 154
            $this->_sourceRules = [
223 154
                [[$this->sourceAttribute], 'required'],
224 154
                [[$this->sourceAttribute], 'string'],
225
            ];
226
        }
227 155
        return $this->_sourceRules;
228
    }
229
230
    /**
231
     * Set the rules associated with source attribute.
232
     * @param array $rules
233
     */
234 1
    public function setSourceRules($rules)
235
    {
236 1
        if (!empty($rules) && is_array($rules)) {
237 1
            $this->_sourceRules = $rules;
238
        }
239 1
    }
240
241
    /**
242
     * Initialize the source attribute with $sourceSelf.
243
     * This method is ONLY used for being triggered by event. DO NOT call,
244
     * override or modify it directly, unless you know the consequences.
245
     * @param ModelEvent $event
246
     */
247 161
    public function onInitSourceAttribute($event)
248
    {
249 161
        $sender = $event->sender;
250 161
        $sourceAttribute = $sender->sourceAttribute;
251 161
        $sender->$sourceAttribute = static::$sourceSelf;
252 161
    }
253
}
254