Passed
Push — master ( 02be02...16ebe1 )
by Aleksandr
04:27
created

Uploader   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 266
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 266
rs 8.2608
c 0
b 0
f 0
wmc 40

21 Methods

Rating   Name   Duplication   Size   Complexity  
A process() 0 20 4
A getFileNameWithOutExtension() 0 3 1
A getUserId() 0 8 2
A formAliasPath() 0 7 2
A formUid() 0 7 2
A formAttributes() 0 15 2
A data() 0 4 1
A getMimeType() 0 3 1
A getUid() 0 3 2
A processFilePath() 0 13 4
B copy() 0 8 5
A slug() 0 4 1
A delete() 0 4 1
A getFileName() 0 3 2
A getSession() 0 8 3
A folder() 0 4 1
A getFileExtension() 0 6 2
A generateUid() 0 4 1
A getNewFileAlias() 0 3 1
A loadAttributes() 0 3 1
A name() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Uploader 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 Uploader, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace carono\yii2file;
4
5
use Yii;
6
use yii\base\Component;
7
use yii\base\Security;
8
use yii\db\ActiveRecord;
9
use yii\db\Expression;
10
use yii\helpers\ArrayHelper;
11
use yii\helpers\FileHelper;
12
use yii\web\UploadedFile;
13
14
/**
15
 * Class FileUpload
16
 *
17
 * @package carono\components
18
 * @property string $fullName
19
 */
20
class Uploader extends Component
21
{
22
    /**
23
     * @var FileUploadTrait
24
     */
25
    public $modelClass;
26
    public $data;
27
    public $file;
28
    public $name;
29
    public $slug;
30
    public $uid;
31
    public $delete = true;
32
    public $folder;
33
34
    protected $fileName;
35
    protected $filePath;
36
37
    /**
38
     * @param $name
39
     * @return $this
40
     */
41
    public function name($name)
42
    {
43
        $this->name = $name;
44
        return $this;
45
    }
46
47
    /**
48
     * @param $data
49
     * @return $this
50
     */
51
    public function data($data)
52
    {
53
        $this->data = $data;
54
        return $this;
55
    }
56
57
    /**
58
     * @param $path
59
     * @return $this
60
     */
61
    public function folder($path)
62
    {
63
        $this->folder = $path;
64
        return $this;
65
    }
66
67
    /**
68
     * @param bool $deleteOnFinish
69
     * @return $this
70
     */
71
    public function delete($deleteOnFinish = true)
72
    {
73
        $this->delete = $deleteOnFinish;
74
        return $this;
75
    }
76
77
    /**
78
     * @return null|string
79
     */
80
    protected function getSession()
81
    {
82
        if (isset(Yii::$app->session)) {
83
            $session = Yii::$app->session->getIsActive() ? Yii::$app->session->getId() : null;
84
        } else {
85
            $session = null;
86
        }
87
        return $session;
88
    }
89
90
    /**
91
     * @return mixed
92
     */
93
    public function getFileName()
94
    {
95
        return $this->name ?: $this->fileName;
96
    }
97
98
    /**
99
     * @return string
100
     */
101
    protected function getFileNameWithOutExtension()
102
    {
103
        return basename($this->getFileName(), '.' . $this->getFileExtension());
104
    }
105
106
    /**
107
     * @return string
108
     */
109
    protected function getMimeType()
110
    {
111
        return FileHelper::getMimeType($this->filePath);
112
    }
113
114
    /**
115
     * @return mixed|string
116
     */
117
    protected function getFileExtension()
118
    {
119
        if (!$extension = strtolower(pathinfo($this->fileName, PATHINFO_EXTENSION))) {
120
            $extension = ArrayHelper::getValue(FileHelper::getExtensionsByMimeType($this->getMimeType()), 0);
121
        }
122
        return $extension;
123
    }
124
125
    /**
126
     * @return int|null|string
127
     */
128
    public function getUserId()
129
    {
130
        if (isset(Yii::$app->user)) {
131
            $userId = Yii::$app->user->getId();
132
        } else {
133
            $userId = null;
134
        }
135
        return $userId;
136
    }
137
138
    /**
139
     * @param $source
140
     * @param $destination
141
     * @throws \Exception
142
     */
143
    public function copy($source, $destination)
144
    {
145
        if (is_uploaded_file($source)) {
146
            if (!move_uploaded_file($source, $destination)) {
147
                throw new \Exception('Unknown upload error');
148
            }
149
        } elseif ($this->delete ? !rename($source, $destination) : !copy($source, $destination)) {
150
            throw new \Exception('Failed to write file to disk');
151
        }
152
    }
153
154
    /**
155
     * @return string
156
     */
157
    public function getUid()
158
    {
159
        return $this->uid = $this->uid ?: $this->formUid();
160
    }
161
162
    /**
163
     * @return string
164
     */
165
    public function getNewFileAlias()
166
    {
167
        return static::formAliasPath($this->getUid(), $this->folder);
168
    }
169
170
    /**
171
     * @param ActiveRecord $model
172
     * @param $attributes
173
     */
174
    public function loadAttributes($model, $attributes)
175
    {
176
        $model->setAttributes($attributes);
177
    }
178
179
    public function formAttributes()
180
    {
181
        $this->processFilePath($this->file);
182
        return [
183
            'session' => $this->getSession(),
184
            'name' => $this->getFileNameWithOutExtension(),
185
            'extension' => $this->getFileExtension(),
186
            'user_id' => $this->getUserId(),
187
            'uid' => $this->getUid(),
188
            'data' => !is_null($this->data) ? json_encode($this->data) : null,
189
            'mime_type' => $this->getMimeType(),
190
            'md5' => md5_file($this->filePath),
191
            'folder' => static::formAliasPath($this->getUid(), $this->folder),
192
            'slug' => $this->slug,
193
            'size' => filesize($this->filePath)
194
        ];
195
    }
196
197
    /**
198
     * @return FileUploadTrait|null
199
     * @throws \Exception
200
     */
201
    public function process()
202
    {
203
        /**
204
         * @var FileUploadTrait $model
205
         */
206
        $model = new $this->modelClass();
207
        $this->loadAttributes($model, $this->formAttributes());
0 ignored issues
show
Bug introduced by
$model of type carono\yii2file\FileUploadTrait is incompatible with the type yii\db\ActiveRecord expected by parameter $model of carono\yii2file\Uploader::loadAttributes(). ( Ignorable by Annotation )

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

207
        $this->loadAttributes(/** @scrutinizer ignore-type */ $model, $this->formAttributes());
Loading history...
208
        $newFilePath = $model->getRealFilePath();
209
        if (!is_dir($realFolder = dirname($newFilePath))) {
210
            mkdir($realFolder, 0777, true);
211
        }
212
        if (!file_exists($this->filePath)) {
213
            throw new \Exception('File not loaded or not exist');
214
        }
215
        $this->copy($this->filePath, $newFilePath);
216
        if ($model->save()) {
0 ignored issues
show
Bug introduced by
It seems like save() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

216
        if ($model->/** @scrutinizer ignore-call */ save()) {
Loading history...
217
            return $model;
218
        } else {
219
            $model->deleteFile();
220
            return null;
221
        }
222
    }
223
224
    /**
225
     * @param $file
226
     */
227
    protected function processFilePath($file)
228
    {
229
        if (strpos($file, 'http') === 0) {
230
            $tmp = Yii::getAlias('@runtime') . DIRECTORY_SEPARATOR . uniqid("fu");
231
            file_put_contents($tmp, file_get_contents($file));
232
            $this->filePath = $tmp;
233
            $this->fileName = basename($file);
234
        } elseif (is_string($file)) {
235
            $this->filePath = Yii::getAlias($file);
236
            $this->fileName = basename($this->filePath);
237
        } elseif ($file instanceof UploadedFile) {
238
            $this->filePath = $file->tempName;
239
            $this->fileName = $file->name;
240
        }
241
    }
242
243
    /**
244
     * @param $slug
245
     * @return $this
246
     */
247
    public function slug($slug)
248
    {
249
        $this->slug = $slug;
250
        return $this;
251
    }
252
253
    /**
254
     * @return string
255
     */
256
    protected function generateUid()
257
    {
258
        $sec = new Security();
259
        return md5($sec->generateRandomString(64));
260
    }
261
262
    /**
263
     * @return string
264
     */
265
    protected function formUid()
266
    {
267
        $class = $this->modelClass;
268
        do {
269
            $uPath = $this->generateUid();
270
        } while ($class::find()->where(["uid" => $uPath])->exists());
271
        return $uPath;
272
    }
273
274
    /**
275
     * @param $path
276
     * @param null $aliasPrefix
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $aliasPrefix is correct as it would always require null to be passed?
Loading history...
277
     * @return string
278
     */
279
    public static function formAliasPath($path, $aliasPrefix = null)
280
    {
281
        $p = [$aliasPrefix];
282
        for ($i = 0; $i < 3; $i++) {
283
            $p[] = $path[$i];
284
        }
285
        return join('/', $p);
286
    }
287
}