Completed
Push — master ( 831484...fa61bb )
by Andrey
01:37
created

ProfileValidate::checkProfileModel()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 9

Duplication

Lines 10
Ratio 71.43 %

Importance

Changes 0
Metric Value
dl 10
loc 14
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 3
nop 1
1
<?php
2
3
namespace Itstructure\UsersModule\models;
4
5
use yii\db\ActiveRecordInterface;
6
use yii\helpers\ArrayHelper;
7
use yii\web\IdentityInterface;
8
use yii\rbac\ManagerInterface;
9
use yii\base\{Model, InvalidConfigException};
10
use Itstructure\UsersModule\interfaces\ModelInterface;
11
12
/**
13
 * Class for validation user fields.
14
 *
15
 * @property array  $rules
16
 * @property array  $attributes
17
 * @property array  $attributeLabels
18
 * @property bool  $rbacManage
19
 * @property bool  $customRewrite
20
 * @property IdentityInterface|ActiveRecordInterface  $profileModel
21
 * @property ManagerInterface  $authManager
22
 * @property string  $name
23
 * @property string  $login
24
 * @property string  $email
25
 * @property integer  $status
26
 * @property string  $password
27
 * @property string  $passwordRepeat
28
 *
29
 * @package Itstructure\UsersModule\models
30
 */
31
class ProfileValidate extends Model implements ModelInterface
32
{
33
    /**
34
     * Validate fields with rules.
35
     *
36
     * @var array
37
     */
38
    public $rules = [];
39
40
    /**
41
     * Attributes.
42
     *
43
     * @var array
44
     */
45
    public $attributes = [];
46
47
    /**
48
     * Attribute labels.
49
     *
50
     * @var array
51
     */
52
    public $attributeLabels = [];
53
54
    /**
55
     * Set manage for roles.
56
     *
57
     * @var bool
58
     */
59
    public $rbacManage = false;
60
61
    /**
62
     * Rewrite rules, labels, attributes by custom.
63
     *
64
     * @var bool
65
     */
66
    public $customRewrite = false;
67
68
    /**
69
     * Current profile (user) model.
70
     *
71
     * @var IdentityInterface|ActiveRecordInterface
72
     */
73
    private $profileModel;
74
75
    /**
76
     * Auth manager.
77
     *
78
     * @var ManagerInterface
79
     */
80
    private $authManager;
81
82
    /**
83
     * Scenarios constants.
84
     */
85
    const SCENARIO_CREATE = 'create';
86
    const SCENARIO_UPDATE = 'update';
87
88
    /**
89
     * Initialize.
90
     */
91
    public function init()
92
    {
93
        if ($this->rbacManage && null === $this->authManager){
94
            throw new InvalidConfigException('The authManager is not defined.');
95
        }
96
    }
97
98
    /**
99
     * @inheritdoc
100
     */
101
    public function rules()
102
    {
103
        $rules = $this->customRewrite ? $this->rules : ArrayHelper::merge(
104
            [
105
                'required' => [
106
                    [
107
                        'name',
108
                        'login',
109
                        'email',
110
                        'status'
111
                    ],
112
                    'required',
113
                ],
114
                'requiredOnCreate' => [
115
                    [
116
                        'password',
117
                        'passwordRepeat',
118
                    ],
119
                    'required',
120
                    'on' => self::SCENARIO_CREATE,
121
                ],
122
                'string' => [
123
                    [
124
                        'name',
125
                        'login',
126
                        'email',
127
                        'password',
128
                        'passwordRepeat',
129
                    ],
130
                    'string',
131
                    'max' => 255,
132
                ],
133
                'integer' => [
134
                    [
135
                        'status',
136
                    ],
137
                    'integer',
138
                ],
139
                'name' => [
140
                    'name',
141
                    'unique',
142
                    'skipOnError'     => true,
143
                    'targetClass'     => \Yii::$app->user->identityClass,
144
                    'targetAttribute' => ['name' => 'name'],
145
                    'filter' => $this->getScenario() == self::SCENARIO_UPDATE ? 'id != '.$this->id : ''
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Itstructure\Users...models\ProfileValidate>. 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...
146
                ],
147
                'login' => [
148
                    'login',
149
                    'unique',
150
                    'skipOnError'     => true,
151
                    'targetClass'     => \Yii::$app->user->identityClass,
152
                    'targetAttribute' => ['login' => 'login'],
153
                    'filter' => $this->getScenario() == self::SCENARIO_UPDATE ? 'id != '.$this->id : ''
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Itstructure\Users...models\ProfileValidate>. 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...
154
                ],
155
                'email' => [
156
                    'email',
157
                    'unique',
158
                    'skipOnError'     => true,
159
                    'targetClass'     => \Yii::$app->user->identityClass,
160
                    'targetAttribute' => ['email' => 'email'],
161
                    'filter' => $this->getScenario() == self::SCENARIO_UPDATE ? 'id != '.$this->id : ''
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Itstructure\Users...models\ProfileValidate>. 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...
162
                ],
163
                'password' => [
164
                    'password',
165
                    'compare',
166
                    'compareAttribute' => 'passwordRepeat',
167
                ],
168
                'passwordRepeat' => [
169
                    'passwordRepeat',
170
                    'compare',
171
                    'compareAttribute' => 'password',
172
                ]
173
            ],
174
            $this->rules
175
        );
176
177
        return $this->rbacManage ? ArrayHelper::merge(
178
            $rules,
179
            [
180
                'requiredRoles' => [
181
                    'roles',
182
                    'required',
183
                ],
184
                'validateRoles' => [
185
                    'roles',
186
                    'validateRoles',
187
                ],
188
            ]
189
        ) : $rules;
190
    }
191
192
    /**
193
     * Scenarios.
194
     *
195
     * @return array
196
     */
197
    public function scenarios()
198
    {
199
        return [
200
            self::SCENARIO_CREATE => $this->attributes(),
201
            self::SCENARIO_UPDATE => $this->attributes(),
202
            self::SCENARIO_DEFAULT => $this->attributes(),
203
        ];
204
    }
205
206
    /**
207
     * List if attributes.
208
     *
209
     * @return array
210
     */
211
    public function attributes()
212
    {
213
        $attributes = $this->customRewrite ? $this->attributes : ArrayHelper::merge(
214
            [
215
                'name',
216
                'login',
217
                'email',
218
                'status',
219
                'password',
220
                'passwordRepeat',
221
            ],
222
            $this->attributes
223
        );
224
225
        return $this->rbacManage ? ArrayHelper::merge(
226
            $attributes,
227
            [
228
                'roles',
229
            ]
230
        ) : $attributes;
231
    }
232
233
    /**
234
     * List if attribute labels.
235
     *
236
     * @inheritdoc
237
     */
238
    public function attributeLabels()
239
    {
240
        $attributeLabels = $this->customRewrite ? $this->attributeLabels : ArrayHelper::merge(
241
            [
242
                'name' => 'Name',
243
                'login' => 'Login',
244
                'email' => 'Email',
245
                'status' => 'Status',
246
                'password' => 'Password',
247
                'passwordRepeat' => 'Password confirm',
248
            ],
249
            $this->attributeLabels
250
        );
251
252
        return $this->rbacManage ? ArrayHelper::merge(
253
            $attributeLabels,
254
            [
255
                'roles' => 'Roles',
256
            ]
257
        ) : $attributeLabels;
258
    }
259
260
    /**
261
     * Get field value.
262
     *
263
     * @param string $name field name.
264
     *
265
     * @return mixed
266
     */
267
    public function __get($name)
268
    {
269
        if ($this->profileModel->getIsNewRecord()){
0 ignored issues
show
Bug introduced by
The method getIsNewRecord does only exist in yii\db\ActiveRecordInterface, but not in yii\web\IdentityInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
270
            return $this->{$name} ?? '';
271
        }
272
273
        if ($this->rbacManage && 'roles' === $name){
274
            $roles = $this->authManager->getRolesByUser($this->profileModel->getId());
0 ignored issues
show
Bug introduced by
The method getId does only exist in yii\web\IdentityInterface, but not in yii\db\ActiveRecordInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
275
            return array_keys($roles);
276
        }
277
278
        if ($this->rbacManage && 'authManager' === $name){
279
            return $this->authManager;
280
        }
281
282
        return $this->profileModel->{$name} ?? '';
283
    }
284
285
    /**
286
     * Set field value.
287
     *
288
     * @param string $name  name of field.
289
     * @param mixed  $value value to be stored in field.
290
     *
291
     * @return void
292
     */
293
    public function __set($name, $value)
294
    {
295
        $this->{$name} = $value;
296
    }
297
298
    /**
299
     * Returns profile (user) model.
300
     *
301
     * @return mixed
302
     */
303
    public function getProfileModel()
304
    {
305
        return $this->profileModel;
306
    }
307
308
    /**
309
     * Set profile (user) model.
310
     *
311
     * @param $model.
312
     *
313
     * @throws InvalidConfigException
314
     *
315
     * @return void
316
     */
317
    public function setProfileModel($model): void
318
    {
319
        self::checkProfileModel($model);
320
321
        $this->profileModel = $model;
322
    }
323
324
    /**
325
     * Set auth manager.
326
     *
327
     * @param ManagerInterface $authManager
328
     */
329
    public function setAuthManager(ManagerInterface $authManager): void
330
    {
331
        $this->authManager = $authManager;
332
    }
333
334
    /**
335
     * Validate roles data format.
336
     *
337
     * @param $attribute
338
     *
339
     * @return bool
340
     */
341
    public function validateRoles($attribute): bool
342
    {
343
        if (!is_array($this->roles)){
0 ignored issues
show
Documentation introduced by
The property roles does not exist on object<Itstructure\Users...models\ProfileValidate>. 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...
344
            $this->addError($attribute, 'Incorrect roles data format.');
345
            return false;
346
        }
347
348
        return true;
349
    }
350
351
    /**
352
     * Save user data.
353
     *
354
     * @return bool
355
     */
356
    public function save(): bool
357
    {
358
        if ($this->profileModel->getIsNewRecord()){
0 ignored issues
show
Bug introduced by
The method getIsNewRecord does only exist in yii\db\ActiveRecordInterface, but not in yii\web\IdentityInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
359
            $this->setScenario(self::SCENARIO_CREATE);
360
        } else {
361
            $this->setScenario(self::SCENARIO_UPDATE);
362
        }
363
364
        if (!$this->validate()){
365
            return false;
366
        }
367
368
        foreach ($this->attributes() as $attribute) {
369
370
            if (null !== $this->{$attribute} && 'roles' !== $attribute){
371
                $this->profileModel->{$attribute} = $this->{$attribute};
372
            }
373
        }
374
375
        if (!$this->profileModel->save()){
0 ignored issues
show
Bug introduced by
The method save does only exist in yii\db\ActiveRecordInterface, but not in yii\web\IdentityInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
376
            return false;
377
        }
378
379
        if ($this->rbacManage){
380
            $this->assignRoles();
381
        }
382
383
        return true;
384
    }
385
386
    /**
387
     * Returns current model id.
388
     *
389
     * @return int
390
     */
391
    public function getId(): int
392
    {
393
        return $this->profileModel->getId();
0 ignored issues
show
Bug introduced by
The method getId does only exist in yii\web\IdentityInterface, but not in yii\db\ActiveRecordInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
394
    }
395
396
    /**
397
     * Check profileModel for instances.
398
     *
399
     * @throws InvalidConfigException
400
     *
401
     * @param $model
402
     *
403
     * @return void
404
     */
405
    public static function checkProfileModel($model)
406
    {
407 View Code Duplication
        if (!($model instanceof ActiveRecordInterface)){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
408
            $modelClass = (new\ReflectionClass($model));
409
            throw new InvalidConfigException($modelClass->getNamespaceName() .
410
                '\\' . $modelClass->getShortName().' class  must be implemented from yii\db\ActiveRecordInterface.');
411
        }
412
413 View Code Duplication
        if (!($model instanceof IdentityInterface)){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
414
            $modelClass = (new\ReflectionClass($model));
415
            throw new InvalidConfigException($modelClass->getNamespaceName() .
416
                '\\' . $modelClass->getShortName().' class  must be implemented from yii\web\IdentityInterface.');
417
        }
418
    }
419
420
    /**
421
     * Assign roles.
422
     *
423
     * @return void
424
     */
425
    private function assignRoles(): void
426
    {
427
        if (!$this->profileModel->getIsNewRecord()){
0 ignored issues
show
Bug introduced by
The method getIsNewRecord does only exist in yii\db\ActiveRecordInterface, but not in yii\web\IdentityInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
428
            $this->authManager->revokeAll(
429
                $this->profileModel->getId()
0 ignored issues
show
Bug introduced by
The method getId does only exist in yii\web\IdentityInterface, but not in yii\db\ActiveRecordInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
430
            );
431
        }
432
433
        foreach ($this->roles as $role){
0 ignored issues
show
Documentation introduced by
The property roles does not exist on object<Itstructure\Users...models\ProfileValidate>. 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...
434
            $role = $this->authManager->getRole($role);
435
436
            if (null === $role){
437
                continue;
438
            }
439
440
            $this->authManager->assign($role, $this->profileModel->getId());
441
        }
442
    }
443
}
444