Code

< 40 %
40-60 %
> 60 %
1
<?php
2
/**
3
 * View.php
4
 * @author Revin Roman
5
 * @link https://rmrevin.ru
6
 */
7
8
namespace rmrevin\yii\minify;
9
10
use yii\base\Event;
11
use yii\helpers\FileHelper;
12
use yii\web\AssetBundle;
13
use yii\web\Response;
14
15
/**
16
 * Class View
17
 * @package rmrevin\yii\minify
18
 */
19
class View extends \yii\web\View
20
{
21
22
    /**
23
     * @var bool
24
     */
25
    public $enableMinify = true;
26
27
    /**
28
     * @var string filemtime or sha1
29
     */
30
    public $fileCheckAlgorithm = 'hash';
31
32
    /**
33
     * @var bool
34
     */
35
    public $concatCss = true;
36
37
    /**
38
     * @var bool
39
     */
40
    public $minifyCss = true;
41
42
    /**
43
     * @var array
44
     */
45
    public $cssOptions = [];
46
47
    /**
48
     * @var bool
49
     */
50
    public $concatJs = true;
51
52
    /**
53
     * @var bool
54
     */
55
    public $minifyJs = true;
56
57
    /**
58
     * @var bool
59
     */
60
    public $minifyOutput = false;
61
62
    /**
63
     * @var string path alias to web base (in url)
64
     */
65
    public $webPath = '@web';
66
67
    /**
68
     * @var string path alias to web base (absolute)
69
     */
70
    public $basePath = '@webroot';
71
72
    /**
73
     * @var string path alias to save minify result
74
     */
75
    public $minifyPath = '@webroot/minify';
76
77
    /**
78
     * @var array positions of js files to be minified
79
     */
80
    public $jsPosition = [self::POS_END, self::POS_HEAD];
81
82
    /**
83
     * @var array options of minified js files
84
     */
85
    public $jsOptions = [];
86
87
    /**
88
     * @var bool|string charset forcibly assign, otherwise will use all of the files found charset
89
     */
90
    public $forceCharset = false;
91
92
    /**
93
     * @var bool whether to change @import on content
94
     */
95
    public $expandImports = true;
96
97
    /**
98
     * @var int|bool chmod of minified file. If false chmod not set
99
     */
100
    public $fileMode = 0664;
101
102
    /**
103
     * @var array schemes that will be ignored during normalization url
104
     */
105
    public $schemas = ['//', 'http://', 'https://', 'ftp://'];
106
107
    /**
108
     * @var array options for compressing output result
109
     *
110
     * 'cssMinifier' : (optional) callback function to process content of STYLE
111
     * elements.
112
     *
113
     * 'jsMinifier' : (optional) callback function to process content of SCRIPT
114
     * elements. Note: the type attribute is ignored.
115
     *
116
     * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
117
     * unset, minify will sniff for an XHTML doctype.
118
     */
119
    public $compressOptions = [];
120
121
    /**
122
     * @var array
123
     */
124
    public $excludeBundles = [];
125
126
    /**
127
     * @var array
128
     */
129
    public $excludeFiles = [];
130
131
    /**
132
     * @var array
133
     */
134
    public $hashAlgos = ['md5', 'tiger160,3', 'sha1', 'tiger192,4'];
135
136
    /**
137
     * @var null|string
138
     */
139
    public $currentHashAlgo;
140
141
    /**
142
     * @var \yii\caching\CacheInterface|string|null
143
     */
144
    public $cache;
145
146
    /**
147
     * @throws \rmrevin\yii\minify\Exception
148
     * @throws \yii\base\InvalidConfigException
149
     * @throws \yii\base\InvalidParamException
150
     * @throws \yii\base\Exception
151
     */
152 11
    public function init()
153
    {
154 11
        parent::init();
155
156 11
        $this->basePath = \Yii::getAlias($this->basePath);
157 11
        $this->webPath = \Yii::getAlias($this->webPath);
158 11
        $this->minifyPath = \Yii::getAlias($this->minifyPath);
159
160 11
        if (null !== $this->cache && is_string($this->cache)) {
161 11
            $this->cache = \Yii::$app->get($this->cache);
162
        }
163
164 11
        foreach ($this->excludeBundles as $bundleClass) {
165 1
            if (!class_exists($bundleClass)) {
166
                continue;
167
            }
168
169
            /** @var AssetBundle $Bundle */
170 1
            $Bundle = new $bundleClass;
171
172 1
            if (!empty($Bundle->css)) {
173 1
                $this->excludeFiles = array_merge($this->excludeFiles, $Bundle->css);
174
            }
175
176 1
            if (!empty($Bundle->js)) {
177 1
                $this->excludeFiles = array_merge($this->excludeFiles, $Bundle->js);
178
            }
179
        }
180
181 11
        $hashAlgos = hash_algos();
182
183 11
        foreach ($this->hashAlgos as $alog) {
184 11
            if (!in_array($alog, $hashAlgos, true)) {
185
                continue;
186
            }
187
188 11
            $this->currentHashAlgo = $alog;
189 11
            break;
190
        }
191
192 11
        if (null === $this->currentHashAlgo) {
193
            throw new Exception('Unable to determine the hash algorithm.');
194
        }
195
196 11
        $minifyPath = $this->minifyPath;
197
198 11
        if (!file_exists($minifyPath)) {
199 11
            FileHelper::createDirectory($minifyPath);
200
        }
201
202 11
        if (!is_readable($minifyPath)) {
203
            throw new Exception('Directory for compressed assets is not readable.');
204
        }
205
206 11
        if (!is_writable($minifyPath)) {
207
            throw new Exception('Directory for compressed assets is not writable.');
208
        }
209
210 11
        if (true === $this->enableMinify && true === $this->minifyOutput) {
211
            \Yii::$app->response->on(Response::EVENT_BEFORE_SEND, [$this, 'compressOutput']);
212
        }
213 11
    }
214
215
    /**
216
     * @param \yii\base\Event $event
217
     * @codeCoverageIgnore
218
     */
219
    public function compressOutput(Event $event)
220
    {
221
        /** @var Response $Response */
222
        $Response = $event->sender;
223
224
        if (Response::FORMAT_HTML !== $Response->format) {
225
            return;
226
        }
227
228
        if (!empty($Response->data)) {
229
            $Response->data = \Minify_HTML::minify($Response->data, $this->compressOptions);
230
        }
231
232
        if (!empty($Response->content)) {
233
            $Response->content = \Minify_HTML::minify($Response->content, $this->compressOptions);
234
        }
235
    }
236
237
    /**
238
     * @inheritdoc
239
     */
240 9
    public function endBody()
241
    {
242 9
        $this->trigger(self::EVENT_END_BODY);
243
244 9
        echo self::PH_BODY_END;
245
246 9
        foreach (array_keys($this->assetBundles) as $bundle) {
247 9
            $this->registerAssetFiles($bundle);
248
        }
249
250 9
        if (true === $this->enableMinify) {
251 9
            (new components\CSS($this))->export();
252 9
            (new components\JS($this))->export();
253
        }
254 9
    }
255
}
256