Completed
Push — master ( 85769a...b67e6b )
by Igor
07:14
created

SignupProviderForm::saveUser()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 16
ccs 0
cts 13
cp 0
rs 9.2
cc 4
eloc 9
nc 4
nop 0
crap 20

1 Method

Rating   Name   Duplication   Size   Complexity  
A SignupProviderForm::login() 0 5 1
1
<?php
2
3
namespace app\models\forms;
4
5
use Yii;
6
use yii\base\DynamicModel;
7
use yii\helpers\FileHelper;
8
use yii\web\UploadedFile;
9
use yii\base\Exception;
10
use yii\base\UserException;
11
use app\models\User;
12
use app\models\UserProfile;
13
use app\services\Tokenizer;
14
15
class SignupProviderForm extends \yii\base\Model
16
{
17
    /**
18
     * @var string
19
     */
20
    public $email;
21
    /**
22
     * @var \app\models\User
23
     */
24
    private $user = null;
25
26
    /**
27
     * @param User $user
28
     */
29
    public function __construct($user, $email)
30
    {
31
        $this->user = $user;
32
        $this->email = $email;
33
    }
34
35
    /**
36
     * @inheritdoc
37
     */
38
    public function rules()
39
    {
40
        return [
41
            ['email', 'filter', 'filter' => 'trim'],
42
            ['email', 'required'],
43
            ['email', 'string', 'max' => 255],
44
            ['email', 'email'],
45
            ['email', 'unique',
46
                'targetClass' => '\app\models\User',
47
                'message' => Yii::t('app.msg', 'This email address has already been taken')
48
            ],
49
        ];
50
    }
51
52
    /**
53
     * @inheritdoc
54
     */
55
    public function attributeLabels()
56
    {
57
        return [
58
            'email' => Yii::t('app', 'Email'),
59
        ];
60
    }
61
62
    /**
63
     * Create manually UploadedFile instance by file path
64
     *
65
     * @param string $path file path
66
     * @return UploadedFile
67
     */
68
    private function makeUploadedFile(string $path): UploadedFile
69
    {
70
        $tmpFile = tempnam(sys_get_temp_dir(), 'app');
71
        file_put_contents($tmpFile, file_get_contents($path));
72
73
        $uploadedFile = new UploadedFile();
74
        $uploadedFile->name = strtok(pathinfo($path, PATHINFO_BASENAME), '?');
75
        $uploadedFile->tempName = $tmpFile;
76
        $uploadedFile->type = FileHelper::getMimeType($tmpFile);
77
        $uploadedFile->size = filesize($tmpFile);
78
        $uploadedFile->error = 0;
79
80
        return $uploadedFile;
81
    }
82
83
    /**
84
     * Save photo
85
     *
86
     * @param \app\models\UserProfile $profile
87
     * @param string $photo
88
     * @return void
89
     */
90
    private function savePhoto(UserProfile $profile, string $photo): void
91
    {
92
        $file = $this->makeUploadedFile($photo);
93
        $model = new DynamicModel(compact('file'));
94
        $model->addRule('file', 'image', $profile->fileRules('photo', true))->validate();
0 ignored issues
show
Documentation Bug introduced by
The method fileRules does not exist on object<app\models\UserProfile>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
95
        if (!$model->hasErrors()) {
96
            $profile->createFile('photo', $file->tempName, $model->file->name);
0 ignored issues
show
Documentation Bug introduced by
The method createFile does not exist on object<app\models\UserProfile>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
97
        } else {
98
            $profile->photo = '';
99
        }
100
    }
101
102
    /**
103
     * Login
104
     */
105
    public function login(): void
106
    {
107
        $this->user->updateDateLogin();
108
        Yii::$app->user->login($this->user, 3600 * 24 * 30);
109
    }
110
111
    /**
112
     * Signs user up
113
     *
114
     * @throws Exception
115
     * @return \app\models\User
116
     */
117
    public function signup(): User
118
    {
119
        $this->user->email = $this->email;
120
121
        $profile = $this->user->profile;
0 ignored issues
show
Documentation introduced by
The property profile does not exist on object<app\models\User>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
122
        if ($profile->isNewRecord && !empty($profile->photo)) {
123
            $this->savePhoto($profile, $profile->photo);
124
        }
125
126
        $this->user->status = User::STATUS_ACTIVE;
127
128
        if (!$this->user->save()) {
129
            throw new Exception(Yii::t('app.msg', 'An error occurred while saving user'));
130
        }
131
132
        $this->login();
133
134
        return $this->user;
135
    }
136
137
    /**
138
     * Sends an email with a link, for confirm the email
139
     *
140
     * @throws UserException
141
     */
142
    public function sendEmail(): void
143
    {
144
        $tokenizer = new Tokenizer();
145
        if (!$tokenizer->validate($this->user->email_confirm_token)) {
146
            $this->user->setEmailConfirmToken($tokenizer->generate());
147
            $this->user->updateAttributes([
148
                'email_confirm_token' => $this->user->email_confirm_token,
149
                'date_confirm' => $this->user->date_confirm,
150
            ]);
151
        }
152
153
        $sent = Yii::$app->notify->sendMessage(
154
            $this->email,
155
            Yii::t('app', 'Activate Your Account'),
156
            'emailConfirmToken',
157
            ['user' => $this->user]
158
        );
159
160
        if (!$sent) {
161
            throw new UserException(Yii::t('app.msg', 'An error occurred while sending a message to activate account'));
162
        }
163
    }
164
}
165