Completed
Push — master ( ea324c...2e8bb7 )
by Andrey
01:33
created

BaseUpload::rules()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 84

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 84
c 0
b 0
f 0
rs 8.349
nc 2
cc 2
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Itstructure\MFUploader\models\upload;
4
5
use yii\base\{Model, InvalidConfigException};
6
use yii\web\UploadedFile;
7
use yii\imagine\Image;
8
use Itstructure\MFUploader\Module;
9
use Itstructure\MFUploader\models\Mediafile;
10
use Itstructure\MFUploader\interfaces\{ThumbConfigInterface, UploadModelInterface};
11
12
/**
13
 * Class BaseUpload
14
 *
15
 * @property string $alt Alt text for the file.
16
 * @property string $title Title for the file.
17
 * @property string $description File description.
18
 * @property string $subDir Addition sub-directory for uploaded files.
19
 * @property string $owner Owner name (post, page, article e.t.c.).
20
 * @property int $ownerId Owner id.
21
 * @property string $ownerAttribute Owner attribute (image, audio, thumbnail e.t.c.).
22
 * @property string $neededFileType Needed file type for validation (thumbnail, image e.t.c.).
23
 * @property bool $renameFiles Rename file after upload.
24
 * @property array $fileExtensions File extensions.
25
 * @property bool $checkExtensionByMimeType Check extension by MIME type (they are must match).
26
 * @property int $fileMaxSize Maximum file size.
27
 * @property array $thumbsConfig Thumbs config with their types and sizes.
28
 * @property string $thumbFilenameTemplate Thumbnails name template.
29
 * Default template: {original}-{width}-{height}-{alias}.{extension}
30
 * @property array $uploadDirs Directories for uploaded files depending on the file type.
31
 * @property string $uploadDir Directory for uploaded files.
32
 * @property string $uploadPath Full directory path to upload file.
33
 * @property string $outFileName Prepared file name to save in database and storage.
34
 * @property string $databaseUrl File url path for database.
35
 * @property UploadedFile $file File object.
36
 * @property Mediafile $mediafileModel Mediafile model to save files data.
37
 *
38
 * @package Itstructure\MFUploader\models
39
 *
40
 * @author Andrey Girnik <[email protected]>
41
 */
42
abstract class BaseUpload extends Model
43
{
44
    /**
45
     * Scripts Constants.
46
     * Required for certain validation rules to work for specific scenarios.
47
     */
48
    const SCENARIO_UPLOAD = 'upload';
49
    const SCENARIO_UPDATE = 'update';
50
51
    /**
52
     * Alt text for the file.
53
     *
54
     * @var string
55
     */
56
    public $alt;
57
58
    /**
59
     * Title for the file.
60
     *
61
     * @var string
62
     */
63
    public $title;
64
65
    /**
66
     * File description.
67
     *
68
     * @var string
69
     */
70
    public $description;
71
72
    /**
73
     * Addition sub-directory for uploaded files.
74
     *
75
     * @var string
76
     */
77
    public $subDir;
78
79
    /**
80
     * Owner name (post, page, article e.t.c.).
81
     *
82
     * @var string
83
     */
84
    public $owner;
85
86
    /**
87
     * Owner id.
88
     *
89
     * @var int
90
     */
91
    public $ownerId;
92
93
    /**
94
     * Owner attribute (image, audio, thumbnail e.t.c.).
95
     *
96
     * @var string
97
     */
98
    public $ownerAttribute;
99
100
    /**
101
     * Needed file type for validation (thumbnail, image e.t.c.).
102
     *
103
     * @var string
104
     */
105
    public $neededFileType;
106
107
    /**
108
     * Rename file after upload.
109
     *
110
     * @var bool
111
     */
112
    public $renameFiles = true;
113
114
    /**
115
     * File extensions.
116
     *
117
     * @var array
118
     */
119
    public $fileExtensions = [
120
        UploadModelInterface::FILE_TYPE_THUMB => [
121
            'png', 'jpg', 'jpeg', 'gif',
122
        ],
123
        UploadModelInterface::FILE_TYPE_IMAGE => [
124
            'png', 'jpg', 'jpeg', 'gif',
125
        ],
126
        UploadModelInterface::FILE_TYPE_AUDIO => [
127
            'mp3',
128
        ],
129
        UploadModelInterface::FILE_TYPE_VIDEO => [
130
            'mp4', 'ogg', 'ogv', 'oga', 'ogx', 'webm',
131
        ],
132
        UploadModelInterface::FILE_TYPE_APP => [
133
            'doc', 'docx', 'rtf', 'pdf', 'rar', 'zip', 'jar', 'mcd', 'xls',
134
        ],
135
        UploadModelInterface::FILE_TYPE_TEXT => [
136
            'txt',
137
        ],
138
        UploadModelInterface::FILE_TYPE_OTHER => null,
139
    ];
140
141
    /**
142
     * Check extension by MIME type (they are must match).
143
     *
144
     * @var bool
145
     */
146
    public $checkExtensionByMimeType = true;
147
148
    /**
149
     * Maximum file size.
150
     *
151
     * @var int
152
     */
153
    public $fileMaxSize = 1024*1024*64;
154
155
    /**
156
     * Thumbs config with their types and sizes.
157
     *
158
     * @var array
159
     */
160
    public $thumbsConfig = [];
161
162
    /**
163
     * Thumbnails name template.
164
     * Values can be the next: {original}, {width}, {height}, {alias}, {extension}
165
     *
166
     * @var string
167
     */
168
    public $thumbFilenameTemplate = '{original}-{width}-{height}-{alias}.{extension}';
169
170
    /**
171
     * Directories for uploaded files depending on the file type.
172
     *
173
     * @var array
174
     */
175
    public $uploadDirs;
176
177
    /**
178
     * Directory for uploaded files.
179
     *
180
     * @var string
181
     */
182
    protected $uploadDir;
183
184
    /**
185
     * Full directory path to upload file.
186
     *
187
     * @var string
188
     */
189
    protected $uploadPath;
190
191
    /**
192
     * Prepared file name to save in database and storage.
193
     *
194
     * @var string
195
     */
196
    protected $outFileName;
197
198
    /**
199
     * File url path for database.
200
     *
201
     * @var string
202
     */
203
    protected $databaseUrl;
204
205
    /**
206
     * File object.
207
     *
208
     * @var UploadedFile
209
     */
210
    private $file;
211
212
    /**
213
     * Mediafile model to save files data.
214
     *
215
     * @var Mediafile
216
     */
217
    private $mediafileModel;
218
219
    /**
220
     * Set params for send file.
221
     *
222
     * @return void
223
     */
224
    abstract protected function setParamsForSend(): void;
225
226
    /**
227
     * Set some params for delete.
228
     *
229
     * @return void
230
     */
231
    abstract protected function setParamsForDelete(): void;
232
233
    /**
234
     * Send file to local directory or send file to remote storage.
235
     *
236
     * @return bool
237
     */
238
    abstract protected function sendFile(): bool;
239
240
    /**
241
     * Delete files from local directory or from remote storage.
242
     *
243
     * @return void
244
     */
245
    abstract protected function deleteFiles(): void;
246
247
    /**
248
     * Create thumb.
249
     *
250
     * @param ThumbConfigInterface $thumbConfig
251
     *
252
     * @return string|null
253
     */
254
    abstract protected function createThumb(ThumbConfigInterface $thumbConfig);
255
256
    /**
257
     * Get storage type (local, s3, e.t.c...).
258
     *
259
     * @return string
260
     */
261
    abstract protected function getStorageType(): string;
262
263
    /**
264
     * Actions after main save.
265
     *
266
     * @return mixed
267
     */
268
    abstract protected function afterSave();
269
270
    /**
271
     * Scenarios.
272
     *
273
     * @return array
274
     */
275
    public function scenarios(): array
276
    {
277
        return [
278
            self::SCENARIO_UPLOAD => $this->attributes(),
279
            self::SCENARIO_UPDATE => $this->attributes(),
280
        ];
281
    }
282
283
    /**
284
     * Attributes.
285
     *
286
     * @return array
287
     */
288
    public function attributes()
289
    {
290
        return [
291
            'file',
292
            'subDir',
293
            'owner',
294
            'ownerId',
295
            'ownerAttribute',
296
            'neededFileType',
297
            'alt',
298
            'title',
299
            'description',
300
        ];
301
    }
302
303
        /**
304
     * {@inheritdoc}
305
     */
306
    public function rules()
307
    {
308
        return [
309
            [
310
                [
311
                    'neededFileType',
312
                ],
313
                'string',
314
                'on' => [
315
                    self::SCENARIO_UPLOAD,
316
                    self::SCENARIO_UPDATE,
317
                ],
318
            ],
319
            [
320
                'file',
321
                'required',
322
                'on' => [
323
                    self::SCENARIO_UPLOAD,
324
                ],
325
            ],
326
            [
327
                'file',
328
                'file',
329
                'on' => [
330
                    self::SCENARIO_UPLOAD,
331
                    self::SCENARIO_UPDATE,
332
                ],
333
                'skipOnEmpty' => true,
334
                'extensions' => array_key_exists($this->neededFileType, $this->fileExtensions) ?
335
                    $this->fileExtensions[$this->neededFileType] : null,
336
                'checkExtensionByMimeType' => $this->checkExtensionByMimeType,
337
                'maxSize' => $this->fileMaxSize
338
            ],
339
            [
340
                'subDir',
341
                'string',
342
                'on' => [
343
                    self::SCENARIO_UPLOAD,
344
                    self::SCENARIO_UPDATE,
345
                ],
346
                'max' => 24,
347
            ],
348
            [
349
                'subDir',
350
                'filter',
351
                'on' => [
352
                    self::SCENARIO_UPLOAD,
353
                    self::SCENARIO_UPDATE,
354
                ],
355
                'filter' => function($value) {
356
                    return trim($value, DIRECTORY_SEPARATOR);
357
                }
358
            ],
359
            [
360
                [
361
                    'alt',
362
                    'title',
363
                    'description',
364
                ],
365
                'string',
366
                'on' => [
367
                    self::SCENARIO_UPLOAD,
368
                    self::SCENARIO_UPDATE,
369
                ],
370
            ],
371
            [
372
                [
373
                    'owner',
374
                    'ownerAttribute',
375
                ],
376
                'string',
377
                'on' => [
378
                    self::SCENARIO_UPLOAD,
379
                ],
380
            ],
381
            [
382
                'ownerId',
383
                'integer',
384
                'on' => [
385
                    self::SCENARIO_UPLOAD,
386
                ],
387
            ],
388
        ];
389
    }
390
391
    /**
392
     * Set mediafile model.
393
     *
394
     * @param Mediafile $model
395
     */
396
    public function setMediafileModel(Mediafile $model): void
397
    {
398
        $this->mediafileModel = $model;
399
    }
400
401
    /**
402
     * Get mediafile model.
403
     *
404
     * @return Mediafile
405
     */
406
    public function getMediafileModel(): Mediafile
407
    {
408
        return $this->mediafileModel;
409
    }
410
411
    /**
412
     * Set file.
413
     *
414
     * @param UploadedFile|null $file
415
     *
416
     * @return void
417
     */
418
    public function setFile(UploadedFile $file = null): void
419
    {
420
        $this->file = $file;
421
    }
422
423
    /**
424
     * Set file.
425
     *
426
     * @return mixed
427
     */
428
    public function getFile()
429
    {
430
        return $this->file;
431
    }
432
433
    /**
434
     * Save file in the storage and database by using a "mediafileModel".
435
     *
436
     * @throws \Exception
437
     *
438
     * @return bool
439
     */
440
    public function save(): bool
441
    {
442
        if ($this->mediafileModel->isNewRecord) {
443
            $this->setScenario(self::SCENARIO_UPLOAD);
444
        } else {
445
            $this->setScenario(self::SCENARIO_UPDATE);
446
        }
447
448
        if (!$this->validate()) {
449
            return false;
450
        }
451
452
        if (null !== $this->file) {
453
454
            $this->setParamsForSend();
455
456
            if (!$this->sendFile()) {
457
                throw new \Exception('Error upload file.', 500);
458
            }
459
460
            if ($this->getScenario() == self::SCENARIO_UPDATE) {
461
                $this->setParamsForDelete();
462
                $this->deleteFiles();
463
            }
464
465
            $this->mediafileModel->url = $this->databaseUrl;
466
            $this->mediafileModel->filename = $this->outFileName;
467
            $this->mediafileModel->size = $this->file->size;
468
            $this->mediafileModel->type = $this->file->type;
469
            $this->mediafileModel->storage = $this->getStorageType();
470
        }
471
472
        $this->mediafileModel->alt = $this->alt;
473
        $this->mediafileModel->title = $this->title;
474
        $this->mediafileModel->description = $this->description;
475
476
        if (!$this->mediafileModel->save()) {
477
            throw new \Exception('Error save file data in database.', 500);
478
        }
479
480
        $this->afterSave();
481
482
        return true;
483
    }
484
485
    /**
486
     * Delete files from local directory or from remote storage.
487
     *
488
     * @throws \Exception
489
     *
490
     * @return int
491
     */
492
    public function delete(): int
493
    {
494
        $this->setParamsForDelete();
495
496
        $this->deleteFiles();
497
498
        $deleted = $this->mediafileModel->delete();
499
500
        if (false === $deleted) {
501
            throw new \Exception('Error delete file data from database.', 500);
502
        }
503
504
        return $deleted;
505
    }
506
507
    /**
508
     * Returns current model id.
509
     *
510
     * @return int|string
511
     */
512
    public function getId()
513
    {
514
        return $this->mediafileModel->id;
515
    }
516
517
    /**
518
     * Create thumbs for this image
519
     *
520
     * @throws InvalidConfigException
521
     *
522
     * @return bool
523
     */
524
    public function createThumbs(): bool
525
    {
526
        $thumbs = [];
527
528
        Image::$driver = [Image::DRIVER_GD2, Image::DRIVER_GMAGICK, Image::DRIVER_IMAGICK];
529
530
        foreach ($this->thumbsConfig as $alias => $preset) {
531
            $thumbUrl = $this->createThumb(Module::configureThumb($alias, $preset));
532
            if (null === $thumbUrl) {
533
                continue;
534
            }
535
            $thumbs[$alias] = $thumbUrl;
536
        }
537
538
        // Create default thumb.
539
        if (!array_key_exists(Module::THUMB_ALIAS_DEFAULT, $this->thumbsConfig)) {
540
            $thumbUrlDefault = $this->createThumb(
541
                Module::configureThumb(
542
                    Module::THUMB_ALIAS_DEFAULT,
543
                    Module::getDefaultThumbConfig()
544
                )
545
            );
546
            if (null !== $thumbUrlDefault) {
547
                $thumbs[Module::THUMB_ALIAS_DEFAULT] = $thumbUrlDefault;
548
            }
549
        }
550
551
        $this->mediafileModel->thumbs = serialize($thumbs);
552
553
        return $this->mediafileModel->save();
554
    }
555
556
    /**
557
     * Returns thumbnail name.
558
     *
559
     * @param $original
560
     * @param $extension
561
     * @param $alias
562
     * @param $width
563
     * @param $height
564
     *
565
     * @return string
566
     */
567
    public function getThumbFilename($original, $extension, $alias, $width, $height)
568
    {
569
        return strtr($this->thumbFilenameTemplate, [
570
            '{original}'  => $original,
571
            '{extension}' => $extension,
572
            '{alias}'     => $alias,
573
            '{width}'     => $width,
574
            '{height}'    => $height,
575
        ]);
576
    }
577
578
    /**
579
     * Get upload directory configuration by file type.
580
     *
581
     * @param string $fileType
582
     *
583
     * @throws InvalidConfigException
584
     *
585
     * @return string
586
     */
587
    protected function getUploadDirConfig(string $fileType): string
588
    {
589
        if (!is_array($this->uploadDirs) || empty($this->uploadDirs)) {
590
            throw new InvalidConfigException('The localUploadDirs is not defined.');
591
        }
592
593
        if (strpos($fileType, UploadModelInterface::FILE_TYPE_IMAGE) !== false) {
594
            return $this->uploadDirs[UploadModelInterface::FILE_TYPE_IMAGE];
595
596
        } elseif (strpos($fileType, UploadModelInterface::FILE_TYPE_AUDIO) !== false) {
597
            return $this->uploadDirs[UploadModelInterface::FILE_TYPE_AUDIO];
598
599
        } elseif (strpos($fileType, UploadModelInterface::FILE_TYPE_VIDEO) !== false) {
600
            return $this->uploadDirs[UploadModelInterface::FILE_TYPE_VIDEO];
601
602
        } elseif (strpos($fileType, UploadModelInterface::FILE_TYPE_APP) !== false) {
603
            return $this->uploadDirs[UploadModelInterface::FILE_TYPE_APP];
604
605
        } elseif (strpos($fileType, UploadModelInterface::FILE_TYPE_TEXT) !== false) {
606
            return $this->uploadDirs[UploadModelInterface::FILE_TYPE_TEXT];
607
608
        } else {
609
            return $this->uploadDirs[UploadModelInterface::FILE_TYPE_OTHER];
610
        }
611
    }
612
}
613