Completed
Push — master ( 676fbf...9e1756 )
by Alexander
04:58
created

UploadImageBehavior::init()   C

Complexity

Conditions 7
Paths 13

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7.1929
Metric Value
dl 0
loc 24
ccs 16
cts 19
cp 0.8421
rs 6.7273
cc 7
eloc 14
nc 13
nop 0
crap 7.1929
1
<?php
2
3
namespace mongosoft\file;
4
5
use Imagine\Image\ManipulatorInterface;
6
use Yii;
7
use yii\base\InvalidConfigException;
8
use yii\base\InvalidParamException;
9
use yii\db\BaseActiveRecord;
10
use yii\helpers\ArrayHelper;
11
use yii\helpers\FileHelper;
12
use yii\imagine\Image;
13
14
/**
15
 * UploadImageBehavior automatically uploads image, creates thumbnails and fills
16
 * the specified attribute with a value of the name of the uploaded image.
17
 *
18
 * To use UploadImageBehavior, insert the following code to your ActiveRecord class:
19
 *
20
 * ```php
21
 * use mongosoft\file\UploadImageBehavior;
22
 *
23
 * function behaviors()
24
 * {
25
 *     return [
26
 *         [
27
 *             'class' => UploadImageBehavior::className(),
28
 *             'attribute' => 'file',
29
 *             'scenarios' => ['insert', 'update'],
30
 *             'placeholder' => '@app/modules/user/assets/images/userpic.jpg',
31
 *             'path' => '@webroot/upload/{id}/images',
32
 *             'url' => '@web/upload/{id}/images',
33
 *             'thumbPath' => '@webroot/upload/{id}/images/thumb',
34
 *             'thumbUrl' => '@web/upload/{id}/images/thumb',
35
 *             'thumbs' => [
36
 *                   'thumb' => ['width' => 400, 'quality' => 90],
37
 *                   'preview' => ['width' => 200, 'height' => 200],
38
 *              ],
39
 *         ],
40
 *     ];
41
 * }
42
 * ```
43
 *
44
 * @author Alexander Mohorev <[email protected]>
45
 * @author Alexey Samoylov <[email protected]>
46
 */
47
class UploadImageBehavior extends UploadBehavior
48
{
49
    /**
50
     * @var string
51
     */
52
    public $placeholder;
53
    /**
54
     * @var boolean
55
     */
56
    public $createThumbsOnSave = true;
57
    /**
58
     * @var boolean
59
     */
60
    public $createThumbsOnRequest = false;
61
    /**
62
     * @var array the thumbnail profiles
63
     * - `width`
64
     * - `height`
65
     * - `quality`
66
     */
67
    public $thumbs = [
68
        'thumb' => ['width' => 200, 'height' => 200, 'quality' => 90],
69
    ];
70
    /**
71
     * @var string|null
72
     */
73
    public $thumbPath;
74
    /**
75
     * @var string|null
76
     */
77
    public $thumbUrl;
78
79
80
    /**
81
     * @inheritdoc
82
     */
83 3
    public function init()
84
    {
85 3
        parent::init();
86
87 3
        if ($this->createThumbsOnSave) {
88 3
            if ($this->thumbPath === null) {
89 3
                $this->thumbPath = $this->path;
90 3
            }
91 3
            if ($this->thumbUrl === null) {
92 3
                $this->thumbUrl = $this->url;
93 3
            }
94
95 3
            foreach ($this->thumbs as $config) {
96 3
                $width = ArrayHelper::getValue($config, 'width');
97 3
                $height = ArrayHelper::getValue($config, 'height');
98 3
                if ($height < 1 && $width < 1) {
99
                    throw new InvalidConfigException(sprintf(
100
                        'Length of either side of thumb cannot be 0 or negative, current size ' .
101
                            'is %sx%s', $width, $height
102
                    ));
103
                }
104 3
            }
105 3
        }
106 3
    }
107
108
    /**
109
     * @inheritdoc
110
     */
111 2
    protected function afterUpload()
112
    {
113 2
        parent::afterUpload();
114 2
        if ($this->createThumbsOnSave) {
115 2
            $this->createThumbs();
116 2
        }
117 2
    }
118
119
    /**
120
     * @throws \yii\base\InvalidParamException
121
     */
122 2
    protected function createThumbs()
123
    {
124 2
        $path = $this->getUploadPath($this->attribute);
125 2
        foreach ($this->thumbs as $profile => $config) {
126 2
            $thumbPath = $this->getThumbUploadPath($this->attribute, $profile);
127 2
            if ($thumbPath !== null) {
128 2
                if (!FileHelper::createDirectory(dirname($thumbPath))) {
129
                    throw new InvalidParamException("Directory specified in 'thumbPath' attribute doesn't exist or cannot be created.");
130
                }
131 2
                if (!is_file($thumbPath)) {
132 2
                    $this->generateImageThumb($config, $path, $thumbPath);
133 2
                }
134 2
            }
135 2
        }
136 2
    }
137
138
    /**
139
     * @param string $attribute
140
     * @param string $profile
141
     * @param boolean $old
142
     * @return string
143
     */
144 2
    public function getThumbUploadPath($attribute, $profile = 'thumb', $old = false)
145
    {
146
        /** @var BaseActiveRecord $model */
147 2
        $model = $this->owner;
148 2
        $path = $this->resolvePath($this->thumbPath);
149 2
        $attribute = ($old === true) ? $model->getOldAttribute($attribute) : $model->$attribute;
150 2
        $filename = $this->getThumbFileName($attribute, $profile);
151
152 2
        return $filename ? Yii::getAlias($path . '/' . $filename) : null;
153
    }
154
155
    /**
156
     * @param string $attribute
157
     * @param string $profile
158
     * @return string|null
159
     */
160 1
    public function getThumbUploadUrl($attribute, $profile = 'thumb')
161 1
    {
162
        /** @var BaseActiveRecord $model */
163
        $model = $this->owner;
164
        $path = $this->getUploadPath($attribute, true);
165
        if (is_file($path)) {
166
            if ($this->createThumbsOnRequest) {
167
                $this->createThumbs();
168
            }
169
            $url = $this->resolvePath($this->thumbUrl);
170
            $fileName = $model->getOldAttribute($attribute);
171
            $thumbName = $this->getThumbFileName($fileName, $profile);
172
173
            return Yii::getAlias($url . '/' . $thumbName);
174
        } elseif ($this->placeholder) {
175
            return $this->getPlaceholderUrl($profile);
176
        } else {
177
            return null;
178
        }
179
    }
180
181
    /**
182
     * @param $profile
183
     * @return string
184
     */
185
    protected function getPlaceholderUrl($profile)
186
    {
187
        list ($path, $url) = Yii::$app->assetManager->publish($this->placeholder);
188
        $filename = basename($path);
189
        $thumb = $this->getThumbFileName($filename, $profile);
190
        $thumbPath = dirname($path) . DIRECTORY_SEPARATOR . $thumb;
191
        $thumbUrl = dirname($url) . '/' . $thumb;
192
193
        if (!is_file($thumbPath)) {
194
            $this->generateImageThumb($this->thumbs[$profile], $path, $thumbPath);
195
        }
196
197
        return $thumbUrl;
198
    }
199
200
    /**
201
     * @inheritdoc
202
     */
203 1
    protected function delete($attribute, $old = false)
204
    {
205 1
        parent::delete($attribute, $old);
206
207 1
        $profiles = array_keys($this->thumbs);
208 1
        foreach ($profiles as $profile) {
209 1
            $path = $this->getThumbUploadPath($attribute, $profile, $old);
210 1
            if (is_file($path)) {
211
                unlink($path);
212
            }
213 1
        }
214 1
    }
215
216
    /**
217
     * @param $filename
218
     * @param string $profile
219
     * @return string
220
     */
221 2
    protected function getThumbFileName($filename, $profile = 'thumb')
222
    {
223 2
        return $profile . '-' . $filename;
224
    }
225
226
    /**
227
     * @param $config
228
     * @param $path
229
     * @param $thumbPath
230
     */
231 2
    protected function generateImageThumb($config, $path, $thumbPath)
232
    {
233 2
        $width = ArrayHelper::getValue($config, 'width');
234 2
        $height = ArrayHelper::getValue($config, 'height');
235 2
        $quality = ArrayHelper::getValue($config, 'quality', 100);
236 2
        $mode = ArrayHelper::getValue($config, 'mode', ManipulatorInterface::THUMBNAIL_INSET);
237
238 2
        if (!$width || !$height) {
239 2
            $image = Image::getImagine()->open($path);
240 2
            $ratio = $image->getSize()->getWidth() / $image->getSize()->getHeight();
241 2
            if ($width) {
242 2
                $height = ceil($width / $ratio);
243 2
            } else {
244
                $width = ceil($height * $ratio);
245
            }
246 2
        }
247
248
        // Fix error "PHP GD Allowed memory size exhausted".
249 2
        ini_set('memory_limit', '512M');
250 2
        Image::thumbnail($path, $width, $height, $mode)->save($thumbPath, ['quality' => $quality]);
251 2
    }
252
}
253