SignupProviderForm::signup()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.6333
c 0
b 0
f 0
cc 4
nc 4
nop 0
1
<?php
2
3
namespace app\modules\auth\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, UserException};
10
use app\models\entity\{User, UserProfile};
11
use app\modules\auth\services\Tokenizer;
12
13
class SignupProviderForm extends \yii\base\Model
14
{
15
    /**
16
     * @var string
17
     */
18
    public $email;
19
    /**
20
     * @var \app\models\entity\User
21
     */
22
    private $user = null;
23
    /**
24
     * @var Tokenizer
25
     */
26
    private $tokenizer;
27
28
    /**
29
     * @param User $user
30
     */
31
    public function __construct(User $user, Tokenizer $tokenizer, $config = [])
32
    {
33
        $this->tokenizer = $tokenizer;
34
        $this->user = $user;
35
        $this->email = $user->email;
36
37
        parent::__construct($config);
38
    }
39
40
    /**
41
     * @inheritdoc
42
     */
43
    public function rules()
44
    {
45
        return [
46
            ['email', 'filter', 'filter' => 'trim'],
47
            ['email', 'required'],
48
            ['email', 'string', 'max' => 255],
49
            ['email', 'email'],
50
            ['email', 'unique',
51
                'targetClass' => '\app\models\entity\User',
52
                'message' => Yii::t('app', 'This email address has already been taken')
53
            ],
54
        ];
55
    }
56
57
    /**
58
     * @inheritdoc
59
     */
60
    public function attributeLabels()
61
    {
62
        return [
63
            'email' => Yii::t('app', 'Email'),
64
        ];
65
    }
66
67
    /**
68
     * Create manually UploadedFile instance by file path
69
     *
70
     * @param string $path file path
71
     * @return UploadedFile
72
     */
73
    private function makeUploadedFile(string $path): UploadedFile
74
    {
75
        $tmpFile = tempnam(sys_get_temp_dir(), 'app');
76
        file_put_contents($tmpFile, file_get_contents($path));
77
78
        $uploadedFile = new UploadedFile();
79
        $uploadedFile->name = strtok(pathinfo($path, PATHINFO_BASENAME), '?');
80
        $uploadedFile->tempName = $tmpFile;
81
        $uploadedFile->type = FileHelper::getMimeType($tmpFile);
82
        $uploadedFile->size = filesize($tmpFile);
83
        $uploadedFile->error = 0;
84
85
        return $uploadedFile;
86
    }
87
88
    /**
89
     * Save photo
90
     *
91
     * @param \app\models\entity\UserProfile $profile
92
     * @param string $photo
93
     * @return void
94
     */
95
    private function savePhoto(UserProfile $profile, string $photo): void
96
    {
97
        $file = $this->makeUploadedFile($photo);
98
        $model = new DynamicModel(compact('file'));
99
        $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\entity\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...
100
        if (!$model->hasErrors()) {
101
            $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\entity\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...
102
        } else {
103
            $profile->photo = '';
104
        }
105
    }
106
107
    /**
108
     * Login
109
     */
110
    public function login(): void
111
    {
112
        $this->user->updateDateLogin();
113
        Yii::$app->user->login($this->user, 3600 * 24 * 30);
114
    }
115
116
    /**
117
     * Signs user up
118
     *
119
     * @throws Exception
120
     * @return \app\models\entity\User
121
     */
122
    public function signup(): User
123
    {
124
        $this->user->email = $this->email;
125
126
        $profile = $this->user->profile;
127
        if ($profile->isNewRecord && !empty($profile->photo)) {
128
            $this->savePhoto($profile, $profile->photo);
129
        }
130
131
        $this->user->status = User::STATUS_ACTIVE;
132
133
        if (!$this->user->save()) {
134
            throw new Exception(Yii::t('app', 'An error occurred while saving user'));
135
        }
136
137
        $this->login();
138
139
        return $this->user;
140
    }
141
142
    /**
143
     * Sends an email with a link, for confirm the email
144
     *
145
     * @throws UserException
146
     */
147
    public function sendEmail(): void
148
    {
149
        if (!$this->tokenizer->validate($this->user->email_confirm_token)) {
150
            $this->user->setEmailConfirmToken($this->tokenizer->generate());
151
            $this->user->updateAttributes([
152
                'email_confirm_token' => $this->user->email_confirm_token,
153
                'date_confirm' => $this->user->date_confirm,
154
            ]);
155
        }
156
157
        $sent = Yii::$app->mailer
158
            ->compose('registration', ['user' => $this->user])
159
            ->setTo($this->email)
160
            ->setSubject(Yii::t('app', 'Registration'))
161
            ->send();
162
163
        if (!$sent) {
164
            throw new UserException(Yii::t('app', 'An error occurred while sending a message to activate account'));
165
        }
166
    }
167
}
168