File   B
last analyzed

Complexity

Total Complexity 44

Size/Duplication

Total Lines 382
Duplicated Lines 0 %

Importance

Changes 15
Bugs 1 Features 5
Metric Value
wmc 44
eloc 128
c 15
b 1
f 5
dl 0
loc 382
rs 8.8798

23 Methods

Rating   Name   Duplication   Size   Complexity  
A attributeLabels() 0 12 1
A getDb() 0 3 1
A beforeSave() 0 6 2
A changeHash() 0 3 1
A rules() 0 6 1
A getRootPath() 0 3 1
A mime_content_type() 0 69 2
A tableName() 0 3 1
C getIcon() 0 29 9
A isSvg() 0 3 1
A getRootPreviewPath() 0 6 2
A isImage() 0 3 1
A deleteFiles() 0 4 1
A afterDelete() 0 4 1
A getPreviewRootPath() 0 5 3
A getWatermark() 0 8 4
A __toString() 0 3 1
A setZeroObject() 0 4 1
A getHref() 0 3 1
A isFile() 0 3 1
A isVideo() 0 3 1
A makeNameWithSize() 0 5 2
A getPreviewWebPath() 0 15 5

How to fix   Complexity   

Complex Class

Complex classes like File often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use File, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: floor12
5
 * Date: 23.06.2016
6
 * Time: 11:23
7
 */
8
9
namespace floor12\files\models;
10
11
12
use ErrorException;
13
use floor12\files\assets\IconHelper;
14
use Yii;
15
use yii\db\ActiveRecord;
16
use yii\helpers\Url;
17
18
19
/**
20
 * @property integer $id
21
 * @property string $class
22
 * @property string $field
23
 * @property integer $object_id
24
 * @property string $title
25
 * @property string $filename
26
 * @property string $content_type
27
 * @property integer $type
28
 * @property integer $video_status
29
 * @property integer $ordering
30
 * @property integer $created
31
 * @property integer $user_id
32
 * @property integer $size
33
 * @property string $hash
34
 * @property string $href
35
 * @property string $icon
36
 * @property string $rootPath
37
 * @property string|null $watermark
38
 */
39
class File extends ActiveRecord
40
{
41
    const DIRECTORY_SEPARATOR = "/";
42
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public static function getDb()
48
    {
49
        return Yii::$app->getModule('files')->db;
50
    }
51
52
    /**
53
     * @inheritdoc
54
     */
55
56
    public static function tableName()
57
    {
58
        return '{{%file}}';
59
    }
60
61
    /**
62
     * Create hash if its empty
63
     * @param bool $insert
64
     * @return bool
65
     */
66
    public function beforeSave($insert)
67
    {
68
        if (!$this->hash) {
69
            $this->changeHash();
70
        }
71
        return parent::beforeSave($insert);
72
    }
73
74
    /**
75
     * Change object hash
76
     */
77
    public function changeHash()
78
    {
79
        $this->hash = md5(time() . rand(99999, 99999999));
80
81
    }
82
83
    /**
84
     * @return string
85
     */
86
    public function getIcon()
87
    {
88
        $icon = IconHelper::FILE;
89
90
        if ($this->content_type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
91
            $icon = IconHelper::FILE_WORD;
92
93
        if ($this->content_type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
94
            $icon = IconHelper::FILE_EXCEL;
95
96
        if ($this->content_type == 'application/vnd.openxmlformats-officedocument.presentationml.presentation')
97
            $icon = IconHelper::FILE_POWERPOINT;
98
99
        if ($this->content_type == 'application/x-zip-compressed')
100
            $icon = IconHelper::FILE_ARCHIVE;
101
102
        if ($this->content_type == 'application/octet-stream')
103
            $icon = IconHelper::FILE_ARCHIVE;
104
105
        if (preg_match('/audio/', $this->content_type))
106
            $icon = IconHelper::FILE_AUDIO;
107
108
        if (preg_match('/pdf/', $this->content_type))
109
            $icon = IconHelper::FILE_PDF;
110
111
        if ($this->type == FileType::VIDEO)
112
            $icon = IconHelper::FILE_VIDEO;
113
114
        return $icon;
115
    }
116
117
    function mime_content_type($filename)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
118
    {
119
        $idx = explode('.', $filename);
120
        $count_explode = count($idx);
121
        $idx = strtolower($idx[$count_explode - 1]);
122
123
        $mimet = array(
124
            'txt' => 'text/plain',
125
            'htm' => 'text/html',
126
            'html' => 'text/html',
127
            'php' => 'text/html',
128
            'css' => 'text/css',
129
            'js' => 'application/javascript',
130
            'json' => 'application/json',
131
            'xml' => 'application/xml',
132
            'swf' => 'application/x-shockwave-flash',
133
            'flv' => 'video/x-flv',
134
135
            // images
136
            'png' => 'image/png',
137
            'jpe' => 'image/jpeg',
138
            'jpeg' => 'image/jpeg',
139
            'jpg' => 'image/jpeg',
140
            'gif' => 'image/gif',
141
            'bmp' => 'image/bmp',
142
            'ico' => 'image/vnd.microsoft.icon',
143
            'tiff' => 'image/tiff',
144
            'tif' => 'image/tiff',
145
            'svg' => 'image/svg+xml',
146
            'svgz' => 'image/svg+xml',
147
148
            // archives
149
            'zip' => 'application/zip',
150
            'rar' => 'application/x-rar-compressed',
151
            'exe' => 'application/x-msdownload',
152
            'msi' => 'application/x-msdownload',
153
            'cab' => 'application/vnd.ms-cab-compressed',
154
155
            // audio/video
156
            'mp3' => 'audio/mpeg',
157
            'qt' => 'video/quicktime',
158
            'mov' => 'video/quicktime',
159
160
            // adobe
161
            'pdf' => 'application/pdf',
162
            'psd' => 'image/vnd.adobe.photoshop',
163
            'ai' => 'application/postscript',
164
            'eps' => 'application/postscript',
165
            'ps' => 'application/postscript',
166
167
            // ms office
168
            'doc' => 'application/msword',
169
            'rtf' => 'application/rtf',
170
            'xls' => 'application/vnd.ms-excel',
171
            'ppt' => 'application/vnd.ms-powerpoint',
172
            'docx' => 'application/msword',
173
            'xlsx' => 'application/vnd.ms-excel',
174
            'pptx' => 'application/vnd.ms-powerpoint',
175
176
177
            // open office
178
            'odt' => 'application/vnd.oasis.opendocument.text',
179
            'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
180
        );
181
182
        if (isset($mimet[$idx])) {
183
            return $mimet[$idx];
184
        } else {
185
            return 'application/octet-stream';
186
        }
187
    }
188
189
    /**
190
     * @inheritdoc
191
     */
192
193
    public function rules()
194
    {
195
        return [
196
            [['class', 'field', 'filename', 'content_type', 'type'], 'required'],
197
            [['object_id', 'type', 'video_status', 'ordering'], 'integer'],
198
            [['class', 'field', 'title', 'filename', 'content_type'], 'string', 'max' => 255],
199
        ];
200
    }
201
202
    /**
203
     * @inheritdoc
204
     */
205
206
    public function attributeLabels()
207
    {
208
        return [
209
            'id' => Yii::t('app', 'ID'),
210
            'class' => Yii::t('app', 'Class'),
211
            'field' => Yii::t('app', 'Field'),
212
            'object_id' => Yii::t('app', 'Object ID'),
213
            'title' => Yii::t('app', 'Title'),
214
            'filename' => Yii::t('app', 'Filename'),
215
            'content_type' => Yii::t('app', 'Con tent Type'),
216
            'type' => Yii::t('app', 'Type'),
217
            'video_status' => Yii::t('app', 'Video Status'),
218
        ];
219
    }
220
221
    /**
222
     * Return root path of preview
223
     * @return string
224
     */
225
226
    public function getRootPreviewPath()
227
    {
228
        if ($this->isSvg())
229
            return $this->getRootPath();
230
231
        return Yii::$app->getModule('files')->storageFullPath . $this->filename . '.jpg';
0 ignored issues
show
Bug introduced by
Are you sure Yii::app->getModule('files')->storageFullPath of type mixed|null|object can be used in concatenation? ( Ignorable by Annotation )

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

231
        return /** @scrutinizer ignore-type */ Yii::$app->getModule('files')->storageFullPath . $this->filename . '.jpg';
Loading history...
232
    }
233
234
    /**
235
     * @return bool
236
     */
237
    public function isSvg()
238
    {
239
        return $this->content_type == 'image/svg+xml';
240
    }
241
242
    /**
243
     * Return root path of image
244
     * @return string
245
     */
246
247
    public function getRootPath()
248
    {
249
        return Yii::$app->getModule('files')->storageFullPath . DIRECTORY_SEPARATOR . $this->filename;
0 ignored issues
show
Bug introduced by
Are you sure Yii::app->getModule('files')->storageFullPath of type mixed|null|object can be used in concatenation? ( Ignorable by Annotation )

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

249
        return /** @scrutinizer ignore-type */ Yii::$app->getModule('files')->storageFullPath . DIRECTORY_SEPARATOR . $this->filename;
Loading history...
250
    }
251
252
253
    /**
254
     * Return web path
255
     * @return string
256
     */
257
258
    public function getHref()
259
    {
260
        return Url::to(['/files/default/get', 'hash' => $this->hash]);
261
    }
262
263
    /**
264
     * @return bool
265
     */
266
    public function isImage(): bool
267
    {
268
        return $this->type == FileType::IMAGE;
269
    }
270
271
    /**
272
     * Delete files from disk
273
     */
274
275
    public function afterDelete()
276
    {
277
        $this->deleteFiles();
278
        parent::afterDelete();
279
    }
280
281
    /**
282
     * Method to read files from any mime types
283
     * @return bool
284
     */
285
286
//    public function imageCreateFromAny()
287
//    {
288
//        $type = exif_imagetype($this->rootPath);
289
//        $allowedTypes = array(
290
//            1, // [] gif
291
//            2, // [] jpg
292
//            3, // [] png
293
//            6   // [] bmp
294
//        );
295
//        if (!in_array($type, $allowedTypes)) {
296
//            return false;
297
//        }
298
//        switch ($type) {
299
//            case 1 :
300
//                $im = imageCreateFromGif($this->rootPath);
301
//                break;
302
//            case 2 :
303
//                $im = imageCreateFromJpeg($this->rootPath);
304
//                break;
305
//            case 3 :
306
//                $im = imageCreateFromPng($this->rootPath);
307
//                break;
308
//            case 6 :
309
//                $im = imageCreateFromBmp($this->rootPath);
310
//                break;
311
//        }
312
//        return $im;
313
//    }
314
315
    /**
316
     * Delete all files
317
     */
318
    public function deleteFiles()
319
    {
320
        $extension = pathinfo($this->rootPath, PATHINFO_EXTENSION);
321
        array_map('unlink', glob(str_replace(".{$extension}", '*', $this->rootPath)));
322
    }
323
324
    /**
325
     * Set object_id to 0 to break link with object
326
     * @return void
327
     */
328
    public function setZeroObject()
329
    {
330
        $this->object_id = 0;
331
        $this->save(false);
332
    }
333
334
    /**
335
     * @return mixed|null
336
     */
337
    public function getWatermark()
338
    {
339
        if (
340
            isset($this->behaviors['files']) &&
341
            isset($this->behaviors['files']->attributes[$this->field]) &&
342
            isset($this->behaviors['files']->attributes[$this->field]['watermark'])
343
        )
344
            return $this->behaviors['files']->attributes[$this->field]['watermark'];
345
    }
346
347
    /**
348
     * @return string
349
     */
350
    public function __toString()
351
    {
352
        return $this->href;
353
    }
354
355
    /**
356
     * Return webp path to preview
357
     * @param int $width
358
     * @param bool $webp
359
     * @return string
360
     * @throws ErrorException
361
     */
362
    public function getPreviewWebPath(int $width = 0, bool $webp = false)
363
    {
364
        if (!file_exists($this->getRootPath()))
365
            return null;
366
367
        if (!$this->isVideo() && !$this->isImage())
368
            throw new ErrorException('Requiested file is not an image and its implsible to resize it.');
369
370
        if (Yii::$app->getModule('files')->hostStatic)
371
            return
372
                Yii::$app->getModule('files')->hostStatic .
0 ignored issues
show
Bug introduced by
Are you sure Yii::app->getModule('files')->hostStatic of type mixed|null|object can be used in concatenation? ( Ignorable by Annotation )

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

372
                /** @scrutinizer ignore-type */ Yii::$app->getModule('files')->hostStatic .
Loading history...
373
                $this->makeNameWithSize($this->filename, $width, $webp) .
374
                "?hash={$this->hash}&width={$width}&webp=" . intval($webp);
375
376
        return Url::toRoute(['/files/default/image', 'hash' => $this->hash, 'width' => $width, 'webp' => $webp]);
377
    }
378
379
    /**
380
     * @return bool
381
     */
382
    public function isVideo(): bool
383
    {
384
        return $this->type == FileType::VIDEO;
385
    }
386
387
    /**
388
     * Creates file paths to file versions
389
     * @param $name
390
     * @param int $width
391
     * @param bool $webp
392
     * @return string
393
     */
394
    public function makeNameWithSize($name, $width = 0, $webp = false)
395
    {
396
        $extension = pathinfo($this->rootPath, PATHINFO_EXTENSION);
397
        $rootPath = str_replace(".{$extension}", '', $name) . "_w" . $width . ".{$extension}";
398
        return str_replace($extension, $webp ? 'webp' : 'jpeg', $rootPath);
399
    }
400
401
    /**
402
     * Returns full path to custom preview version
403
     * @param int $width
404
     * @param bool $webp
405
     * @return string
406
     * @throws ErrorException
407
     */
408
    public function getPreviewRootPath($width = 0, $webp = false)
409
    {
410
        if (!$this->isVideo() && !$this->isImage())
411
            throw new ErrorException('Requiested file is not an image and its implsible to resize it.');
412
        return $this->makeNameWithSize($this->rootPath, $width, $webp);
413
    }
414
415
    /**
416
     * @return bool
417
     */
418
    public function isFile(): bool
419
    {
420
        return $this->type == FileType::FILE;
421
    }
422
423
}
424