Passed
Push — master ( 5a9e1e...a9a8cf )
by Alexey
03:09
created

UploadForm::init()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 2
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 2
nc 1
nop 0
1
<?php
2
3
namespace modules\users\models;
4
5
use Yii;
6
use yii\base\Exception;
7
use yii\base\Model;
8
use yii\web\UploadedFile;
9
use yii\helpers\FileHelper;
10
use yii\imagine\Image;
11
use Imagine\Image\ImageInterface;
12
use modules\users\Module;
13
14
/**
15
 * Class UploadForm
16
 * @package modules\users\models
17
 */
18
class UploadForm extends Model
19
{
20
    const PREFIX_ORIGINAL = 'original_';
21
    const PREFIX_THUMBNAIL = 'thumb_';
22
    const EXTENSIONS = 'png, jpg';
23
24
    /**
25
     * @var UploadedFile
26
     */
27
    public $imageFile;
28
    /**
29
     * Upload directory
30
     * @var string
31
     */
32
    public $directory = '@frontend/runtime/avatars';
33
    /**
34
     * File Name
35
     * @var string
36
     */
37
    public $fileName = 'avatar';
38
    /**
39
     * File extension
40
     * @var string
41
     */
42
    public $fileExtension = 'jpg';
43
    /**
44
     * @var null|int
45
     */
46
    public $width = 540;
47
    /**
48
     * @var null|int
49
     */
50
    public $height;
51
    /**
52
     * @var int
53
     */
54
    public $avatarWidth = 150;
55
    /**
56
     * @var int
57
     */
58
    public $avatarHeight = 150;
59
    /**
60
     * @var int
61
     */
62
    public $avatarQuality = 100;
63
    /**
64
     * @var int
65
     */
66
    public $cropWidth;
67
    /**
68
     * @var int
69
     */
70
    public $cropHeight;
71
    /**
72
     * @var int
73
     */
74
    public $cropX;
75
    /**
76
     * @var int
77
     */
78
    public $cropY;
79
    /**
80
     * @var int
81
     */
82
    public $quality = 80;
83
84
    /**
85
     * @var int
86
     */
87
    public $cropQuality = 100;
88
89
    /**
90
     * Upload path
91
     * @var string
92
     */
93
    private $path = '';
94
95
    /**
96
     * @inheritDoc
97
     */
98
    public function init()
99
    {
100
        parent::init();
101
        $this->path = $this->path ?: $this->getPath(Yii::$app->user->id);
0 ignored issues
show
Bug introduced by
It seems like Yii::app->user->id can also be of type string; however, parameter $id of modules\users\models\UploadForm::getPath() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
        $this->path = $this->path ?: $this->getPath(/** @scrutinizer ignore-type */ Yii::$app->user->id);
Loading history...
Documentation Bug introduced by
It seems like $this->path ?: $this->getPath(Yii::app->user->id) can also be of type boolean. However, the property $path is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
102
    }
103
104
    /**
105
     * Rules
106
     * @inheritDoc
107
     * @return array|array[]
108
     */
109
    public function rules()
110
    {
111
        return [
112
            [['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => self::EXTENSIONS],
113
            [['cropWidth', 'cropHeight', 'cropX', 'cropY'], 'integer']
114
        ];
115
    }
116
117
    /**
118
     * Labels
119
     * @return array
120
     */
121
    public function attributeLabels()
122
    {
123
        return [
124
            'imageFile' => Module::t('module', 'Image'),
125
            'cropWidth' => Module::t('module', 'Crop Width'),
126
            'cropHeight' => Module::t('module', 'Crop Height'),
127
            'cropX' => Module::t('module', 'Crop X'),
128
            'cropY' => Module::t('module', 'Crop Y'),
129
        ];
130
    }
131
132
    /**
133
     * Upload
134
     * @return array|string
135
     * @throws Exception
136
     */
137
    public function upload()
138
    {
139
        if ($this->validate()) {
140
            $this->createDirectory();
141
142
            $fileName = $this->getFileName();
143
            $path = $this->path . DIRECTORY_SEPARATOR . self::PREFIX_ORIGINAL . $fileName;
144
            if ($this->imageFile->saveAs($path)) {
145
                $this->resize();
146
                $this->delete($path);
147
                return $this->path . DIRECTORY_SEPARATOR . self::PREFIX_THUMBNAIL . $fileName;
148
            }
149
        }
150
        return $this->errors;
151
    }
152
153
    /**
154
     * File Name
155
     * @return string
156
     */
157
    public function getFileName()
158
    {
159
        return $this->fileName . '.' . $this->fileExtension;
160
    }
161
162
    /**
163
     * Resize
164
     * @param $width int
165
     * @param $height int
166
     * @return ImageInterface
167
     */
168
    public function resize($width = null, $height = null)
169
    {
170
        $tWidth = $width ?: $this->width;
171
        $tHeight = $height ?: $this->height;
172
        $fileName = $this->getFileName();
173
        $path = $this->path . DIRECTORY_SEPARATOR . self::PREFIX_ORIGINAL . $fileName;
174
        $thumbPath = $this->path . DIRECTORY_SEPARATOR . self::PREFIX_THUMBNAIL . $fileName;
175
        return Image::resize($path, $tWidth, $tHeight)->save($thumbPath, ['quality' => $this->quality]);
176
    }
177
178
    /**
179
     * Crop
180
     * Обрежет по ширине на 150px, по высоте на 150px, начиная по оси X с отметки в 100px и по оси Y с отметки в 100px
181
     * @return ImageInterface
182
     */
183
    public function crop()
184
    {
185
        $fileName = $this->getFileName();
186
        $thumbPath = $this->path . DIRECTORY_SEPARATOR . self::PREFIX_THUMBNAIL . $fileName;
187
        $path = $this->path . DIRECTORY_SEPARATOR . $fileName;
188
        Image::crop($thumbPath, $this->cropWidth, $this->cropHeight, [$this->cropX, $this->cropY])
189
            ->save($path, ['quality' => $this->cropQuality]);
190
        return Image::thumbnail($path, $this->avatarWidth, $this->avatarHeight)->save($path, ['quality' => $this->avatarQuality]);
191
    }
192
193
    /**
194
     * @param int $id
195
     * @return bool
196
     */
197
    public function isThumbFile($id)
198
    {
199
        $fileName = $this->getFileName();
200
        $path = $this->getPath($id) . DIRECTORY_SEPARATOR . self::PREFIX_THUMBNAIL . $fileName;
201
        if (file_exists($path)) {
202
            return true;
203
        }
204
        return false;
205
    }
206
207
    /**
208
     * Delete file
209
     * @param string|array $path
210
     * @return bool
211
     */
212
    public function delete($path)
213
    {
214
        if (is_array($path)) {
215
            foreach ($path as $item) {
216
                if (file_exists($item)) {
217
                    FileHelper::unlink($item);
218
                }
219
            }
220
        } else if (file_exists($path)) {
221
            FileHelper::unlink($path);
222
        }
223
        return true;
224
    }
225
226
    /**
227
     * @param int $id
228
     * @return bool|string
229
     */
230
    public function getPath($id)
231
    {
232
        $this->path = Yii::getAlias($this->directory . '/' . $id);
0 ignored issues
show
Documentation Bug introduced by
It seems like Yii::getAlias($this->directory . '/' . $id) can also be of type boolean. However, the property $path is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
233
        return $this->path;
234
    }
235
236
    /**
237
     * Create directory
238
     * @return bool
239
     * @throws Exception
240
     */
241
    public function createDirectory()
242
    {
243
        return FileHelper::createDirectory($this->path, 0777);
244
    }
245
}
246