Completed
Push — master ( 3b2b8f...105307 )
by vistart
04:36
created

User::createProfile()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 1
Metric Value
dl 0
loc 13
rs 9.2
c 1
b 0
f 1
ccs 9
cts 9
cp 1
cc 4
eloc 9
nc 3
nop 1
crap 4
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\user;
14
15
use rhosocial\base\models\models\BaseUserModel;
16
use rhosocial\base\models\queries\BaseBlameableQuery;
17
use rhosocial\user\models\log\UserLoginTrait;
18
use rhosocial\user\security\UserPasswordHistoryTrait;
19
use Yii;
20
use yii\base\Event;
21
use yii\behaviors\AttributeBehavior;
22
use yii\caching\TagDependency;
23
use yii\db\ActiveRecord;
24
25
/**
26
 * Common User Model.
27
 * This model should be stored in a relational database. You can create a foreign
28
 * key constraint on other models and this model.
29
 *
30
 * If you're using MySQL, we recommend that you create a data table using the following statement:
31
 *
32
 * ```
33
 * CREATE TABLE `user` (
34
 *   `guid` varbinary(16) NOT NULL COMMENT 'GUID',
35
 *   `id` varchar(16) COLLATE utf8_unicode_ci NOT NULL COMMENT 'ID',
36
 *   `pass_hash` varchar(80) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Password Hash',
37
 *   `ip` varbinary(16) NOT NULL DEFAULT '0' COMMENT 'IP',
38
 *   `ip_type` tinyint(3) unsigned NOT NULL DEFAULT '4' COMMENT 'IP Address Type',
39
 *   `created_at` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT 'Create Time',
40
 *   `updated_at` datetime NOT NULL DEFAULT '1970-01-01 00:00:00' COMMENT 'Update Time',
41
 *   `auth_key` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Authentication Key',
42
 *   `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Access Token',
43
 *   `password_reset_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Password Reset Token',
44
 *   `status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT 'Status',
45
 *   `type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Type',
46
 *   `source` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'Source',
47
 *   PRIMARY KEY (`guid`),
48
 *   UNIQUE KEY `user_id_unique` (`id`),
49
 *   KEY `user_auth_key_normal` (`auth_key`),
50
 *   KEY `user_access_token_normal` (`access_token`),
51
 *   KEY `user_password_reset_token` (`password_reset_token`),
52
 *   KEY `user_create_time_normal` (`created_at`)
53
 * ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='User';
54
 * ```
55
 *
56
 * The fields of User table in database are following:
57
 * @property string $guid User's GUID. This property is used to uniquely identify a user.
58
 * This property is automatically generated when the class is created, we do not
59
 * recommend that you modify this property, unless you know the consequences of doing so.
60
 * This property is also regareded as the foreign key target of other models associated
61
 * with this model. If you have to modify this property, the foreign key constraints
62
 * should be updating and deleting on cascade.
63
 * @property string $id User Identifier No. It is a 8-digit number beginning with 4 by default.
64
 * @property string $pass_hash Password Hash.
65
 * We strongly recommend you NOT to change this property directly!
66
 * If you want to set or reset password, please use setPassword() magic property instead.
67
 * @property integer $ip IP address.
68
 * @property integer $ipType
69
 * @property string $createdAt
70
 * @property string $updatedAt
71
 * @property string $auth_key
72
 * @property string $access_token
73
 * @property string $password_reset_token
74
 * @property integer $status
75
 * @property integer $type
76
 * @property string $source
77
 *
78
 * @property-read Profile $profile Profile. This magic property is read-only.
79
 * If you want to modify anyone property of Profile model, please get it first,
80
 * then change and save it, like following:
81
 * ```php
82
 * $profile = $user->profile;
83
 * $profile->nickname = 'vistart';
84
 * $profile->save();
85
 * ```
86
 * If $profileClass is `false`, `null` returned.
87
 * @version 1.0
88
 * @author vistart <[email protected]>
89
 */
90
class User extends BaseUserModel
91
{
92
    use UserPasswordHistoryTrait, UserLoginTrait;
93
    public $searchClass = UserSearch::class;
94
    public function getSearchModel()
95
    {
96
        $class = $this->searchClass;
97
        if (empty($class) || !class_exists($class)) {
98
            return null;
99
        }
100
        return new $class;
101
    }
102
103
    /**
104
     * @inheritdoc
105
     */
106 1
    public function attributeLabels()
107
    {
108
        return [
109 1
            $this->guidAttribute => Yii::t('user', 'GUID'),
110 1
            $this->idAttribute => Yii::t('user', 'ID'),
111 1
            $this->passwordHashAttribute => Yii::t('user', 'Password Hash'),
112 1
            $this->ipAttribute => Yii::t('user', 'IP Address'),
113 1
            $this->ipTypeAttribute => Yii::t('user', 'IP Address Type'),
114 1
            $this->createdAtAttribute => Yii::t('user', 'Creation Time'),
115 1
            $this->updatedAtAttribute => Yii::t('user', 'Last Updated Time'),
116 1
            $this->authKeyAttribute => Yii::t('user', 'Authentication Key'),
117 1
            $this->accessTokenAttribute => Yii::t('user', 'Access Token'),
118 1
            $this->passwordResetTokenAttribute => Yii::t('user', 'Password Reset Token'),
119 1
            $this->statusAttribute => Yii::t('user', 'Status'),
120 1
            'type' => Yii::t('user', 'Type'),
121 1
            $this->sourceAttribute => Yii::t('user', 'Source'),
122 1
            'createdAt' => Yii::t('user', 'Registration Time'),
123 1
            'updatedAt' => Yii::t('user', 'Last Updated Time'),
124
        ];
125
    }
126
127
    /**
128
     * @inheritdoc
129
     */
130
    public $idAttributeType = 1;
131
132
    /**
133
     * @inheritdoc
134
     */
135
    public $idAttributeLength = 8;
136
137
    /**
138
     * @inheritdoc
139
     */
140
    public $idAttributePrefix = '4';
141
142
    /**
143
     * @var bool
144
     */
145
    public $idPreassigned = true;
146
147
    /**
148
     * @inheritdoc
149
     */
150 41
    public static function tableName()
151
    {
152 41
        return '{{%user}}';
153
    }
154
155
    /**
156
     * @var string|false Profile class name. If you do not need profile model,
157
     * please set it false.
158
     */
159
    public $profileClass = false;
160
161
    /**
162
     * @inheritdoc
163
     */
164 41
    public function init()
165
    {
166 41
        $this->on(static::$eventAfterRegister, [$this, 'onAddPasswordToHistory']);
167 41
        $this->on(static::$eventAfterResetPassword, [$this, 'onAddPasswordToHistory']);
168 41
        $this->on(static::EVENT_AFTER_UPDATE, [$this, 'onInvalidTags']);
169 41
        parent::init();
170 41
    }
171
172
    /**
173
     * @var string
174
     */
175
    public $cacheTagPrefix = 'tag_user_';
176
177
    /**
178
     * @return string
179
     */
180 3
    public function getCacheTag()
181
    {
182 3
        return $this->cacheTagPrefix . $this->getID();
183
    }
184
185
    /**
186
     * @param Event $event
187
     */
188 3
    public function onInvalidTags($event)
189
    {
190 3
        $sender = $event->sender;
191
        /*@var $sender static */
192 3
        return TagDependency::invalidate(Yii::$app->cache, $sender->getCacheTag());
193
    }
194
195
    /**
196
     * Create profile.
197
     * If profile of this user exists, it will be returned instead of creating it.
198
     * Meanwhile, the $config parameter will be skipped.
199
     * @param array $config Profile configuration. Skipped if it exists.
200
     * @return Profile
201
     */
202 19
    public function createProfile($config = [])
203
    {
204 19
        $profileClass = $this->profileClass;
205 19
        if (empty($profileClass) || !is_string($this->profileClass)) {
206 1
            return null;
207
        }
208 18
        $profile = $profileClass::findOne($this->getGUID());
209 18
        if (!$profile) {
210 18
            $profile = $this->create($profileClass, $config);
211 18
            $profile->setGUID($this->getGUID());
212
        }
213 18
        return $profile;
214
    }
215
216
    /**
217
     * 
218
     * @return boolean
219
     */
220 4
    public function hasProfile()
221
    {
222 4
        if ($this->profileClass === false || !is_string($this->profileClass) || !class_exists($this->profileClass)) {
223 2
            return false;
224
        }
225 2
        return true;
226
    }
227
228
    /**
229
     * Get Profile query.
230
     * If you want to get profile model, please access this method in magic property way,
231
     * like following:
232
     *
233
     * ```php
234
     * $user->profile;
235
     * ```
236
     *
237
     * @return BaseBlameableQuery
238
     */
239 4
    public function getProfile()
240
    {
241 4
        if (!$this->hasProfile()) {
242 2
            return null;
243
        }
244 2
        $profileClass = $this->profileClass;
245 2
        $profileModel = $profileClass::buildNoInitModel();
246 2
        return $this->hasOne($profileClass,
247 2
                [$profileModel->createdByAttribute => $this->guidAttribute])->inverseOf('user');
248
    }
249
250 36
    public function onGenerateId($event)
251
    {
252 36
        $sender = $event->sender;
253
        /* @var $sender static */
254 36
        return $sender->generateId();
255
    }
256
257
    /**
258
     * @return array
259
     */
260 41
    public function generateIdBehavior()
261
    {
262
        return [
263 41
            'class' => AttributeBehavior::class,
264
            'attributes' => [
265 41
                ActiveRecord::EVENT_BEFORE_INSERT => $this->idAttribute,
266
            ],
267 41
            'value' => [$this, 'onGenerateId'],
268
        ];
269
    }
270
271
    /**
272
     * @return array
273
     */
274 41
    public function behaviors()
275
    {
276 41
        $behaviors = parent::behaviors();
277 41
        $behavior = $this->generateIdBehavior();
278 41
        if (!empty($behavior)) {
279 41
            $behaviors[] = $behavior;
280
        }
281 41
        return $behaviors;
282
    }
283
284
    /**
285
     * @return array
286
     */
287 2
    public function getIdRules()
288
    {
289
        return [
290 2
            [$this->idAttribute, 'safe'],
291
        ];
292
    }
293
}
294