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

File   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 303
Duplicated Lines 0 %

Coupling/Cohesion

Components 5
Dependencies 11

Test Coverage

Coverage 100%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 40
c 6
b 0
f 0
lcom 5
cbo 11
dl 0
loc 303
ccs 89
cts 89
cp 1
rs 8.2608

20 Methods

Rating   Name   Duplication   Size   Complexity  
A tableName() 0 4 1
A attributeLabels() 0 18 1
A behaviors() 0 11 1
A events() 0 6 1
B beforeSave() 0 21 5
A fillUserInfo() 0 7 3
A fillMetaInfo() 0 13 2
A getExtensionByMimeType() 0 19 4
A setStorage() 0 7 1
A getStorage() 0 8 2
A generateName() 0 5 1
A isProtected() 0 4 1
A isUnprotected() 0 4 1
A isTmp() 0 4 1
A getDateOfFile() 0 7 3
B isOwner() 0 8 7
A findAllByOwner() 0 7 1
A findOneByOwner() 0 6 1
A deleteByOwner() 0 9 2
A beforeDelete() 0 5 1

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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
/**
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\models;
10
11
use Yii;
12
use yii\base\InvalidParamException;
13
use yii\behaviors\TimestampBehavior;
14
use yii\helpers\FileHelper;
15
use rkit\filemanager\Storage;
16
17
/**
18
 * ActiveRecord for table "file"
19
 *
20
 * @property integer $id
21
 * @property integer $user_id
22
 * @property integer $owner_id
23
 * @property integer $owner_type
24
 * @property string $title
25
 * @property string $name
26
 * @property integer $size
27
 * @property string $extension
28
 * @property string $mime
29
 * @property string $date_create
30
 * @property string $date_update
31
 * @property integer $ip
32
 * @property integer $tmp
33
 * @property integer $position
34
 * @property integer $protected
35
 */
36
class File extends \yii\db\ActiveRecord
37
{
38
    /**
39
     * @var string
40
     */
41
    public $path;
42
    /**
43
     * @var Storage
44
     */
45
    private $storage;
46
47
    /**
48
     * @inheritdoc
49
     * @codeCoverageIgnore
50
     * @internal
51
     */
52
    public static function tableName()
53
    {
54
        return 'file';
55
    }
56
57
    /**
58
     * @inheritdoc
59
     * @codeCoverageIgnore
60
     * @internal
61
     */
62
    public function attributeLabels()
63
    {
64
        return [
65
            'id' => Yii::t('filemanager-yii2', 'ID'),
66
            'user_id' => Yii::t('filemanager-yii2', 'User'),
67
            'owner_id' => Yii::t('filemanager-yii2', 'Owner'),
68
            'owner_type' => Yii::t('filemanager-yii2', 'Owner type'),
69
            'title' => Yii::t('filemanager-yii2', 'Title'),
70
            'name' => Yii::t('filemanager-yii2', 'Name'),
71
            'size' => Yii::t('filemanager-yii2', 'Size'),
72
            'extension' => Yii::t('filemanager-yii2', 'Extension'),
73
            'mime' => Yii::t('filemanager-yii2', 'Mime'),
74
            'date_create' => Yii::t('filemanager-yii2', 'Date create'),
75
            'date_update' => Yii::t('filemanager-yii2', 'Date update'),
76
            'ip' => Yii::t('filemanager-yii2', 'IP'),
77
            'position' => Yii::t('filemanager-yii2', 'Position'),
78
        ];
79
    }
80
81
    /**
82
     * @inheritdoc
83
     * @internal
84
     */
85 38
    public function behaviors()
86
    {
87
        return [
88
            [
89 38
                'class' => TimestampBehavior::className(),
90 38
                'createdAtAttribute' => 'date_create',
91 38
                'updatedAtAttribute' => 'date_update',
92 38
                'value' => new \yii\db\Expression('NOW()'),
93 38
            ],
94 38
        ];
95
    }
96
97
    /**
98
     * @inheritdoc
99
     * @codeCoverageIgnore
100
     * @internal
101
     */
102
    public function events()
103
    {
104
        return [
105
            \yii\db\ActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete',
106
        ];
107
    }
108
109
    /**
110
     * @internal
111
     */
112 35
    public function beforeSave($insert)
113
    {
114 35
        if (parent::beforeSave($insert)) {
115 35
            if ($insert) {
116 35
                if (!file_exists($this->path)) {
117 1
                    return false;
118
                }
119
120 34
                $this->fillUserInfo();
121 34
                $this->fillMetaInfo();
122
123 34
                if ($this->owner_id === null) {
124 34
                    $this->owner_id = 0;
125 34
                }
126 34
            }
127
128 34
            return true;
129
        }
130
131
        return false; // @codeCoverageIgnore
132
    }
133
134 34
    private function fillUserInfo()
135
    {
136 34
        if (!Yii::$app instanceof \yii\console\Application) {
137
            $this->user_id = Yii::$app->user->isGuest ? 0 : Yii::$app->user->id; // @codeCoverageIgnore
138
            $this->ip = ip2long(Yii::$app->request->getUserIP()); // @codeCoverageIgnore
139
        } // @codeCoverageIgnore
140 34
    }
141
142 34
    private function fillMetaInfo()
143
    {
144 34
        $pathInfo = pathinfo($this->path);
145
146 34
        if ($this->title === null) {
147 6
            $this->title = $pathInfo['filename'];
148 6
        }
149
150 34
        $this->size = filesize($this->path);
151 34
        $this->mime = FileHelper::getMimeType($this->path);
152 34
        $this->extension = $this->getExtensionByMimeType($this->mime);
153 34
        $this->name = $this->generateName();
154 34
    }
155
156
    /**
157
     * Get extension By MimeType
158
     *
159
     * @param string $mimeType MimeType of the file
160
     * @return string
161
     */
162 34
    private function getExtensionByMimeType($mimeType)
163
    {
164 34
        $extensions = FileHelper::getExtensionsByMimeType($mimeType);
165 34
        $pathExtension = pathinfo($this->path, PATHINFO_EXTENSION);
166 34
        $titleExtension = pathinfo($this->title, PATHINFO_EXTENSION);
167
168 34
        if (array_search($pathExtension, $extensions) !== false) {
169 32
            return $pathExtension;
170 2
        } elseif (array_search($titleExtension, $extensions) !== false) {
171 1
            return $titleExtension;
172
        }
173 1
        $extension = explode('/', $mimeType);
174 1
        $extension = end($extension);
175 1
        if (array_search($extension, $extensions) !== false) {
176 1
            return $extension;
177
        }
178
179
        return current($extensions); // @codeCoverageIgnore
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression current($extensions); of type integer|string|false adds false to the return on line 179 which is incompatible with the return type documented by rkit\filemanager\models\...:getExtensionByMimeType of type string. It seems like you forgot to handle an error condition.
Loading history...
180
    }
181
182
    /**
183
     * Set a storage
184
     *
185
     * @param Storage $storage The Strorage for the file
186
     * @return string
187
     */
188 35
    public function setStorage(Storage $storage)
189
    {
190 35
        $this->storage = $storage;
191 35
        $this->storage->setFile($this);
192
193 35
        return $this;
194
    }
195
196
    /**
197
     * Get a storage
198
     *
199
     * @return string
200
     * @throws InvalidParamException
201
     */
202 36
    public function getStorage()
203
    {
204 36
        if ($this->storage === null) {
205 1
            throw new InvalidParamException('The storage is not initialized');
206
        }
207
208 35
        return $this->storage;
209
    }
210
211
    /**
212
     * Generate a name
213
     *
214
     * @return string
215
     */
216 34
    public function generateName()
217
    {
218 34
        $name = date('YmdHis') . substr(md5(microtime() . uniqid()), 0, 10);
219 34
        return $name . '.' . $this->extension;
220
    }
221
222
    /**
223
     * Checks whether the file is protected
224
     *
225
     * @return bool
226
     */
227 35
    public function isProtected()
228
    {
229 35
        return (bool)$this->protected;
230
    }
231
232
    /**
233
     * Checks whether the file is unprotected
234
     *
235
     * @return bool
236
     */
237 3
    public function isUnprotected()
238
    {
239 3
        return (bool)$this->protected === false;
240
    }
241
242
    /**
243
     * Checks whether the file is temp
244
     *
245
     * @return bool
246
     */
247 12
    public function isTmp()
248
    {
249 12
        return (bool)$this->tmp;
250
    }
251
252
    /**
253
     * Get date create of file in format `Ym`
254
     *
255
     * @return string
256
     */
257 34
    public function getDateOfFile()
258
    {
259 34
        if ($this->isNewRecord || is_object($this->date_create)) {
260 34
            return date('Ym');
261
        }
262 23
        return date_format(date_create($this->date_create), 'Ym');
263
    }
264
265
    /**
266
     * Checks whether the owner of the file
267
     *
268
     * @param int $ownerId The id of the owner
269
     * @param int $ownerType The type of the owner
270
     * @return bool
271
     */
272 21
    public function isOwner($ownerId, $ownerType)
273
    {
274 21
        $ownerType = $this->owner_type === $ownerType;
275 21
        $ownerId = $this->owner_id === $ownerId;
276 21
        $user = $this->user_id === Yii::$app->user->id || $this->user_id === 0;
277
278 21
        return (!$this->tmp && $ownerType && $ownerId) || ($this->tmp && $ownerType && $user);
279
    }
280
281
    /**
282
     * Find all by owner
283
     *
284
     * @param int $ownerId The id of the owner
285
     * @param int $ownerType The type of the owner
286
     * @return array
287
     */
288 19
    public static function findAllByOwner($ownerId, $ownerType)
289
    {
290 19
        return static::find()
291 19
            ->where(['owner_id' => $ownerId, 'owner_type' => $ownerType])
292 19
            ->orderBy('position ASC')
293 19
            ->all();
294
    }
295
296
    /**
297
     * Find one by owner
298
     *
299
     * @param int $ownerId The id of the owner
300
     * @param int $ownerType The type of the owner
301
     * @return File|null
302
     */
303 1
    public static function findOneByOwner($ownerId, $ownerType)
304
    {
305 1
        return static::find()
306 1
            ->where(['owner_id' => $ownerId, 'owner_type' => $ownerType])
307 1
            ->one();
308
    }
309
310
    /**
311
     * Delete by owner
312
     *
313
     * @param Storage $storage The storage of the file
314
     * @param int $ownerId The id of the owner
315
     * @param int $ownerType The type of the owner
316
     */
317 3
    public function deleteByOwner($storage, $ownerId, $ownerType)
318
    {
319 3
        $files = self::findAllByOwner($ownerId, $ownerType);
320
321 3
        foreach ($files as $file) {
322 3
            $file->setStorage($storage);
323 3
            $file->delete();
324 3
        }
325 3
    }
326
327
    /**
328
     * Deleting a file from the db and from the file system
329
     * @internal
330
     *
331
     * @return bool
332
     */
333 8
    public function beforeDelete()
334
    {
335 8
        $this->getStorage()->delete();
336 8
        return true;
337
    }
338
}
339