Completed
Push — master ( ab1c63...7944b2 )
by Igor
06:51
created

FileBehavior::createFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

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