Completed
Push — master ( f15f2a...6d9f7a )
by Igor
02:25
created

FileBehavior::afterSave()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 21
ccs 14
cts 14
cp 1
rs 8.7624
cc 6
eloc 12
nc 4
nop 0
crap 6
1
<?php
2
3
/**
4
 * @link https://github.com/rkit/filemanager-yii2
5
 * @copyright Copyright (c) 2015 Igor Romanov
6
 * @license [MIT](http://opensource.org/licenses/MIT)
7
 */
8
9
namespace rkit\filemanager\behaviors;
10
11
use Yii;
12
use yii\base\Behavior;
13
use yii\db\ActiveRecord;
14
use yii\helpers\ArrayHelper;
15
use yii\base\InvalidParamException;
16
use rkit\filemanager\models\File;
17
use rkit\filemanager\helpers\FormatValidation;
18
use rkit\filemanager\behaviors\FileBind;
19
20
class FileBehavior extends Behavior
21
{
22
    /**
23
     * @var array
24
     */
25
    public $attributes = [];
26
    /**
27
     * @var rkit\filemanager\behaviors\FileBind
28
     */
29
    private static $bind;
30
31
    /**
32
     * @internal
33
     */
34 49
    public function init()
35
    {
36 49
        parent::init();
37
38 49
        $this->setBind();
39 49
        Yii::$app->fileManager->registerTranslations();
40 49
    }
41
42
    /**
43
     * @internal
44
     * @return void
45
     */
46 49
    public function setBind()
47
    {
48 49
        $this->bind = new FileBind();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \rkit\filemanager\behaviors\FileBind() of type object<rkit\filemanager\behaviors\FileBind> is incompatible with the declared type object<rkit\filemanager\...ger\behaviors\FileBind> of property $bind.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
49 49
    }
50
51
    /**
52
     * @inheritdoc
53
     * @internal
54
     */
55 49
    public function events()
56
    {
57
        return [
58 49
            ActiveRecord::EVENT_AFTER_INSERT  => 'afterSave',
59 49
            ActiveRecord::EVENT_AFTER_UPDATE  => 'afterSave',
60 49
            ActiveRecord::EVENT_BEFORE_INSERT => 'beforeSave',
61 49
            ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeSave',
62 49
            ActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete',
63 49
        ];
64
    }
65
66
    /**
67
     * @internal
68
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
69
     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
70
     */
71 49
    public function beforeSave($insert)
72
    {
73 49
        foreach ($this->attributes as $attribute => $data) {
74 23
            $oldValue = $this->owner->isNewRecord ? null : $this->owner->getOldAttribute($attribute);
75 23
            $isAttributeChanged = $oldValue === null ? true : $this->owner->isAttributeChanged($attribute);
76
77 23
            $this->attributes[$attribute]['isAttributeChanged'] = $isAttributeChanged;
78 23
            $this->attributes[$attribute]['oldValue'] = $oldValue;
79 23
        }
80 23
    }
81
82
    /**
83
     * @internal
84
     */
85 23
    public function afterSave()
86
    {
87 23
        foreach ($this->attributes as $attribute => $data) {
88 23
            $fileId = $this->owner->{$attribute};
89
90 23
            if ($data['isAttributeChanged'] === false || $fileId === null) {
91 23
                continue;
92
            }
93
94 23
            $storage = $this->getFileStorage($attribute);
95 23
            $ownerId = $this->owner->primaryKey;
96 23
            $ownerType = $this->getFileOwnerType($attribute);
97
98 23
            if ($fileId === [] || $fileId === '') {
99 2
                (new File())->deleteByOwner($storage, $ownerId, $ownerType);
100 2
                continue;
101
            }
102
103 23
            $this->binding($data, $attribute, $storage, $ownerId, $ownerType, $fileId);
104 23
        }
105 23
    }
106
107
    /**
108
     * @internal
109
     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
110
     */
111 1
    public function beforeDelete()
112
    {
113 1
        foreach ($this->attributes as $attribute => $data) {
114 1
            $ownerType = $this->getFileOwnerType($attribute);
115 1
            $storage = $this->getFileStorage($attribute);
116 1
            (new File())->deleteByOwner($storage, $this->owner->primaryKey, $ownerType);
117 1
        }
118 1
    }
119
120
    /**
121
     * Prepare the path of the file
122
     *
123
     * @param array $data
124
     * @param string $attribute
125
     * @param Strorage $storage
126
     * @param int $ownerId
127
     * @param int $ownerType
128
     * @param mixed $fileId
129
     * @return void
130
     */
131 23
    private function binding($data, $attribute, $storage, $ownerId, $ownerType, $fileId)
132
    {
133 23
        if ($this->isMultiple($attribute)) {
134 3
            $this->bind->bindMultiple($storage, $ownerId, $ownerType, $fileId);
135 3
            return;
136
        }
137 20
        $file = $this->bind->bindSingle($storage, $ownerId, $ownerType, $fileId);
138
139 20
        if (isset($data['saveFilePath']) && $data['saveFilePath'] === true) {
140 14
            $value = $this->prepareFilePath($file, $data['oldValue']);
141 20
        } elseif (isset($data['saveFileId']) && $data['saveFileId'] === true) {
142 6
            $value = $this->prepareFileId($file, $data['oldValue']);
143 6
        }
144
145 20
        if (isset($value)) {
146 20
            $this->owner->updateAttributes([$attribute => $value]);
147 20
        }
148 20
    }
149
150
    /**
151
     * Prepare the path of the file
152
     *
153
     * @param mixed $file
154
     * @param mixed $oldValue
155
     * @return string
156
     */
157 14
    private function prepareFilePath($file, $oldValue)
158
    {
159 14
        if (is_object($file)) {
160 12
            return $file->getStorage()->path();
161 4
        } elseif ($file === false && $oldValue !== null) {
162 2
            return $oldValue;
163
        }
164
165 2
        return '';
166
    }
167
168
    /**
169
     * Prepare the id of the file
170
     *
171
     * @param mixed $file
172
     * @param mixed $oldValue
173
     * @return int
174
     */
175 6
    private function prepareFileId($file, $oldValue)
176
    {
177 6
        if (is_object($file)) {
178 4
            return $file->id;
179 3
        } elseif ($file === false && $oldValue !== null) {
180 1
            return $oldValue;
181
        }
182
183 2
        return 0;
184
    }
185
186
    /**
187
     * Get the path to the upload directory
188
     *
189
     * @param string $attribute Attribute of a model
190
     * @return string
191
     */
192 25
    public function uploadDir($attribute)
193
    {
194 25
        if ($this->isFileProtected($attribute)) {
195 6
            return Yii::getAlias(Yii::$app->fileManager->uploadDirProtected);
196
        }
197 19
        return Yii::getAlias(Yii::$app->fileManager->uploadDirUnprotected);
198
    }
199
200
    /**
201
     * Get the type of the owner in as string
202
     *
203
     * @param string $attribute Attribute of a model
204
     * @return string
205
     */
206 36
    private function getStringOwnerType($attribute)
207
    {
208 36
        return $this->owner->tableName() . '.' . $attribute;
209
    }
210
211
    /**
212
     * Get the type of the owner
213
     *
214
     * @param string $attribute Attribute of a model
215
     * @return int
216
     */
217 36
    public function getFileOwnerType($attribute)
218
    {
219 36
        return Yii::$app->fileManager->getOwnerType($this->getStringOwnerType($attribute));
220
    }
221
222
    /**
223
     * Get files
224
     *
225
     * @param string $attribute Attribute of a model
226
     * @return array
227
     */
228 3
    public function getFiles($attribute)
229
    {
230 3
        $files = File::findAllByOwner($this->owner->primaryKey, $this->getFileOwnerType($attribute));
231 3
        foreach ($files as $file) {
232 3
            $file->setStorage($this->getFileStorage($attribute));
233 3
        }
234
235 3
        return $files;
236
    }
237
238
    /**
239
     * Get the file
240
     *
241
     * @param string $attribute Attribute of a model
242
     * @return File|null
243
     */
244 1
    public function getFile($attribute)
245
    {
246 1
        $file = File::findOneByOwner($this->owner->primaryKey, $this->getFileOwnerType($attribute));
247 1
        $file->setStorage($this->getFileStorage($attribute));
248 1
        return $file;
249
    }
250
251
    /**
252
     * Check whether the upload of multiple files
253
     *
254
     * @param string $attribute Attribute of a model
255
     * @return bool
256
     */
257 23
    public function isMultiple($attribute)
258
    {
259 23
        return ArrayHelper::getValue($this->attributes[$attribute], 'multiple', false);
260
    }
261
262
    /**
263
     * Checks whether the file is protected
264
     *
265
     * @param string $attribute Attribute of a model
266
     * @return bool
267
     */
268 35
    public function isFileProtected($attribute)
269
    {
270 35
        return ArrayHelper::getValue($this->attributes[$attribute], 'protected', false);
271
    }
272
273
    /**
274
     * Get rules
275
     *
276
     * @param string $attribute Attribute of a model
277
     * @param bool $onlyCoreValidators Only core validators
278
     * @return array
279
     */
280 28
    public function getFileRules($attribute, $onlyCoreValidators = false)
281
    {
282 28
        $rules = ArrayHelper::getValue($this->attributes[$attribute], 'rules', []);
283 28
        if ($onlyCoreValidators && isset($rules['imageSize'])) {
284 24
            $rules = array_merge($rules, $rules['imageSize']);
285 24
            unset($rules['imageSize']);
286 24
        }
287 28
        return $rules;
288
    }
289
290
    /**
291
     * Get the presets of the file
292
     *
293
     * @param string $attribute Attribute of a model
294
     * @return array
295
     */
296 6
    public function getFilePreset($attribute)
297
    {
298 6
        return array_keys(ArrayHelper::getValue($this->attributes[$attribute], 'preset', []));
299
    }
300
301
    /**
302
     * Get the presets of the file for apply after upload
303
     *
304
     * @param string $attribute Attribute of a model
305
     * @return array
306
     */
307 25
    public function getFilePresetAfterUpload($attribute)
308
    {
309 25
        $preset = ArrayHelper::getValue($this->attributes[$attribute], 'applyPresetAfterUpload', false);
310 25
        if (is_string($preset) && $preset === '*') {
311 6
            return $this->getFilePreset($attribute);
312 19
        } elseif (is_array($preset)) {
313 16
            return $preset;
314
        }
315
316 3
        return [];
317
    }
318
319
    /**
320
     * Get the storage of the file
321
     *
322
     * @param string $attribute Attribute of a model
323
     * @return Storage
324
     * @throws InvalidParamException
325
     */
326 35
    public function getFileStorage($attribute)
327
    {
328 35
        $storage = ArrayHelper::getValue($this->attributes[$attribute], 'storage', null);
329 35
        if ($storage) {
330 35
            return new $storage();
331
        }
332
333
        throw new InvalidParamException('The storage is not defined'); // @codeCoverageIgnore
334
    }
335
336
    /**
337
     * Generate a thumb name
338
     *
339
     * @param string $path The path of the file
340
     * @param string $prefix Prefix for name of the file
341
     * @return string
342
     */
343 25
    public function generateThumbName($path, $prefix)
344
    {
345 25
        $fileName = pathinfo($path, PATHINFO_FILENAME);
346 25
        return str_replace($fileName, $prefix . '_' . $fileName, $path);
347
    }
348
349
    /**
350
     * Resize image
351
     *
352
     * @param string $attribute Attribute of a model
353
     * @param string $preset The name of the preset
354
     * @param string $pathToFile Use this path to the file
355
     * @param bool $returnRealPath Return the real path to the file
356
     * @return string
357
     */
358 25
    public function thumb($attribute, $preset, $pathToFile = null, $returnRealPath = false)
359
    {
360 25
        $realPath = $this->uploadDir($attribute);
361 25
        $publicPath = $pathToFile ? $pathToFile : $this->owner->$attribute;
362 25
        $thumbPath = $this->generateThumbName($publicPath, $preset);
363
364 25
        if (!file_exists($realPath . $thumbPath)) {
365 25
            if (file_exists($realPath . $publicPath)) {
366 25
                $thumbInit = ArrayHelper::getValue($this->attributes[$attribute]['preset'], $preset);
367 25
                if ($thumbInit) {
368 25
                    $thumbInit($realPath, $publicPath, $thumbPath);
369 25
                }
370 25
            }
371 25
        }
372
373 25
        return $returnRealPath ? $realPath . $thumbPath : $thumbPath;
374
    }
375
376
    /**
377
     * Create a file
378
     *
379
     * @param string $attribute Attribute of a model
380
     * @param string $path The path of the file
381
     * @param string $title The title of file
382
     * @param bool $temporary The file is temporary
383
     * @return rkit\filemanager\models\File
384
     */
385 35
    public function createFile($attribute, $path, $title, $temporary)
386
    {
387 35
        $file = new File();
388 35
        $file->path = $path;
389 35
        $file->tmp = $temporary;
390 35
        $file->title = $title;
391 35
        $file->owner_id = $this->owner->primaryKey;
392 35
        $file->owner_type = $this->getFileOwnerType($attribute);
393 35
        $file->protected = $this->isFileProtected($attribute);
394
395 35
        if ($file->save()) {
396 34
            $file->setStorage($this->getFileStorage($attribute));
397 34
            return $file->getStorage()->save($path);
398
        }
399
400
        return false; // @codeCoverageIgnore
401
    }
402
403
    /**
404
     * Get a description of the validation rules in as text
405
     *
406
     * Example
407
     *
408
     * ```php
409
     * $form->field($model, $attribute)->hint($model->getFileRulesDescription($attribute)
410
     * ```
411
     *
412
     * Output
413
     *
414
     * ```
415
     * Min. size of image: 300x300px
416
     * File types: JPG, JPEG, PNG
417
     * Max. file size: 1.049 MB
418
     * ```
419
     *
420
     * @param string $attribute Attribute of a model
421
     * @return string
422
     */
423 9
    public function getFileRulesDescription($attribute)
424
    {
425 9
        return FormatValidation::getDescription($this->attributes[$attribute]['rules']);
426
    }
427
}
428