1 | <?php |
||||||
2 | /** |
||||||
3 | * @link https://www.yiiframework.com/ |
||||||
4 | * @copyright Copyright (c) 2008 Yii Software LLC |
||||||
5 | * @license https://www.yiiframework.com/license/ |
||||||
6 | */ |
||||||
7 | |||||||
8 | namespace yii\web; |
||||||
9 | |||||||
10 | use Yii; |
||||||
11 | use yii\base\InvalidConfigException; |
||||||
12 | use yii\helpers\ArrayHelper; |
||||||
13 | use yii\helpers\Html; |
||||||
14 | use yii\helpers\Url; |
||||||
15 | |||||||
16 | /** |
||||||
17 | * View represents a view object in the MVC pattern. |
||||||
18 | * |
||||||
19 | * View provides a set of methods (e.g. [[render()]]) for rendering purpose. |
||||||
20 | * |
||||||
21 | * View is configured as an application component in [[\yii\base\Application]] by default. |
||||||
22 | * You can access that instance via `Yii::$app->view`. |
||||||
23 | * |
||||||
24 | * You can modify its configuration by adding an array to your application config under `components` |
||||||
25 | * as it is shown in the following example: |
||||||
26 | * |
||||||
27 | * ```php |
||||||
28 | * 'view' => [ |
||||||
29 | * 'theme' => 'app\themes\MyTheme', |
||||||
30 | * 'renderers' => [ |
||||||
31 | * // you may add Smarty or Twig renderer here |
||||||
32 | * ] |
||||||
33 | * // ... |
||||||
34 | * ] |
||||||
35 | * ``` |
||||||
36 | * |
||||||
37 | * For more details and usage information on View, see the [guide article on views](guide:structure-views). |
||||||
38 | * |
||||||
39 | * @property \yii\web\AssetManager $assetManager The asset manager. Defaults to the "assetManager" application |
||||||
40 | * component. |
||||||
41 | * |
||||||
42 | * @author Qiang Xue <[email protected]> |
||||||
43 | * @since 2.0 |
||||||
44 | */ |
||||||
45 | class View extends \yii\base\View |
||||||
46 | { |
||||||
47 | /** |
||||||
48 | * @event Event an event that is triggered by [[beginBody()]]. |
||||||
49 | */ |
||||||
50 | const EVENT_BEGIN_BODY = 'beginBody'; |
||||||
51 | /** |
||||||
52 | * @event Event an event that is triggered by [[endBody()]]. |
||||||
53 | */ |
||||||
54 | const EVENT_END_BODY = 'endBody'; |
||||||
55 | /** |
||||||
56 | * The location of registered JavaScript code block or files. |
||||||
57 | * This means the location is in the head section. |
||||||
58 | */ |
||||||
59 | const POS_HEAD = 1; |
||||||
60 | /** |
||||||
61 | * The location of registered JavaScript code block or files. |
||||||
62 | * This means the location is at the beginning of the body section. |
||||||
63 | */ |
||||||
64 | const POS_BEGIN = 2; |
||||||
65 | /** |
||||||
66 | * The location of registered JavaScript code block or files. |
||||||
67 | * This means the location is at the end of the body section. |
||||||
68 | */ |
||||||
69 | const POS_END = 3; |
||||||
70 | /** |
||||||
71 | * The location of registered JavaScript code block. |
||||||
72 | * This means the JavaScript code block will be enclosed within `jQuery(document).ready()`. |
||||||
73 | */ |
||||||
74 | const POS_READY = 4; |
||||||
75 | /** |
||||||
76 | * The location of registered JavaScript code block. |
||||||
77 | * This means the JavaScript code block will be enclosed within `jQuery(window).load()`. |
||||||
78 | */ |
||||||
79 | const POS_LOAD = 5; |
||||||
80 | /** |
||||||
81 | * This is internally used as the placeholder for receiving the content registered for the head section. |
||||||
82 | */ |
||||||
83 | const PH_HEAD = '<![CDATA[YII-BLOCK-HEAD]]>'; |
||||||
84 | /** |
||||||
85 | * This is internally used as the placeholder for receiving the content registered for the beginning of the body section. |
||||||
86 | */ |
||||||
87 | const PH_BODY_BEGIN = '<![CDATA[YII-BLOCK-BODY-BEGIN]]>'; |
||||||
88 | /** |
||||||
89 | * This is internally used as the placeholder for receiving the content registered for the end of the body section. |
||||||
90 | */ |
||||||
91 | const PH_BODY_END = '<![CDATA[YII-BLOCK-BODY-END]]>'; |
||||||
92 | |||||||
93 | /** |
||||||
94 | * @var AssetBundle[] list of the registered asset bundles. The keys are the bundle names, and the values |
||||||
95 | * are the registered [[AssetBundle]] objects. |
||||||
96 | * @see registerAssetBundle() |
||||||
97 | */ |
||||||
98 | public $assetBundles = []; |
||||||
99 | /** |
||||||
100 | * @var string the page title |
||||||
101 | */ |
||||||
102 | public $title; |
||||||
103 | /** |
||||||
104 | * @var array the registered meta tags. |
||||||
105 | * @see registerMetaTag() |
||||||
106 | */ |
||||||
107 | public $metaTags = []; |
||||||
108 | /** |
||||||
109 | * @var array the registered link tags. |
||||||
110 | * @see registerLinkTag() |
||||||
111 | */ |
||||||
112 | public $linkTags = []; |
||||||
113 | /** |
||||||
114 | * @var array the registered CSS code blocks. |
||||||
115 | * @see registerCss() |
||||||
116 | */ |
||||||
117 | public $css = []; |
||||||
118 | /** |
||||||
119 | * @var array the registered CSS files. |
||||||
120 | * @see registerCssFile() |
||||||
121 | */ |
||||||
122 | public $cssFiles = []; |
||||||
123 | /** |
||||||
124 | * @var array the registered JS code blocks |
||||||
125 | * @see registerJs() |
||||||
126 | */ |
||||||
127 | public $js = []; |
||||||
128 | /** |
||||||
129 | * @var array the registered JS files. |
||||||
130 | * @see registerJsFile() |
||||||
131 | */ |
||||||
132 | public $jsFiles = []; |
||||||
133 | /** |
||||||
134 | * @since 2.0.50 |
||||||
135 | * @var array the script tag options. |
||||||
136 | */ |
||||||
137 | public $scriptOptions = []; |
||||||
138 | |||||||
139 | private $_assetManager; |
||||||
140 | |||||||
141 | |||||||
142 | /** |
||||||
143 | * Whether [[endPage()]] has been called and all files have been registered |
||||||
144 | * @var bool |
||||||
145 | * @since 2.0.44 |
||||||
146 | */ |
||||||
147 | protected $isPageEnded = false; |
||||||
148 | |||||||
149 | /** |
||||||
150 | * Marks the position of an HTML head section. |
||||||
151 | */ |
||||||
152 | 52 | public function head() |
|||||
153 | { |
||||||
154 | 52 | echo self::PH_HEAD; |
|||||
155 | } |
||||||
156 | |||||||
157 | /** |
||||||
158 | * Marks the beginning of an HTML body section. |
||||||
159 | */ |
||||||
160 | 52 | public function beginBody() |
|||||
161 | { |
||||||
162 | 52 | echo self::PH_BODY_BEGIN; |
|||||
163 | 52 | $this->trigger(self::EVENT_BEGIN_BODY); |
|||||
164 | } |
||||||
165 | |||||||
166 | /** |
||||||
167 | * Marks the ending of an HTML body section. |
||||||
168 | */ |
||||||
169 | 56 | public function endBody() |
|||||
170 | { |
||||||
171 | 56 | $this->trigger(self::EVENT_END_BODY); |
|||||
172 | 56 | echo self::PH_BODY_END; |
|||||
173 | |||||||
174 | 56 | foreach (array_keys($this->assetBundles) as $bundle) { |
|||||
175 | 15 | $this->registerAssetFiles($bundle); |
|||||
176 | } |
||||||
177 | } |
||||||
178 | |||||||
179 | /** |
||||||
180 | * Marks the ending of an HTML page. |
||||||
181 | * @param bool $ajaxMode whether the view is rendering in AJAX mode. |
||||||
182 | * If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions |
||||||
183 | * will be rendered at the end of the view like normal scripts. |
||||||
184 | */ |
||||||
185 | 56 | public function endPage($ajaxMode = false) |
|||||
186 | { |
||||||
187 | 56 | $this->trigger(self::EVENT_END_PAGE); |
|||||
188 | |||||||
189 | 56 | $this->isPageEnded = true; |
|||||
190 | |||||||
191 | 56 | $content = ob_get_clean(); |
|||||
192 | |||||||
193 | 56 | echo strtr($content, [ |
|||||
194 | 56 | self::PH_HEAD => $this->renderHeadHtml(), |
|||||
195 | 56 | self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(), |
|||||
196 | 56 | self::PH_BODY_END => $this->renderBodyEndHtml($ajaxMode), |
|||||
197 | 56 | ]); |
|||||
198 | |||||||
199 | 56 | $this->clear(); |
|||||
200 | } |
||||||
201 | |||||||
202 | /** |
||||||
203 | * Renders a view in response to an AJAX request. |
||||||
204 | * |
||||||
205 | * This method is similar to [[render()]] except that it will surround the view being rendered |
||||||
206 | * with the calls of [[beginPage()]], [[head()]], [[beginBody()]], [[endBody()]] and [[endPage()]]. |
||||||
207 | * By doing so, the method is able to inject into the rendering result with JS/CSS scripts and files |
||||||
208 | * that are registered with the view. |
||||||
209 | * |
||||||
210 | * @param string $view the view name. Please refer to [[render()]] on how to specify this parameter. |
||||||
211 | * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file. |
||||||
212 | * @param object|null $context the context that the view should use for rendering the view. If null, |
||||||
213 | * existing [[context]] will be used. |
||||||
214 | * @return string the rendering result |
||||||
215 | * @see render() |
||||||
216 | */ |
||||||
217 | public function renderAjax($view, $params = [], $context = null) |
||||||
218 | { |
||||||
219 | $viewFile = $this->findViewFile($view, $context); |
||||||
220 | |||||||
221 | ob_start(); |
||||||
222 | ob_implicit_flush(false); |
||||||
223 | |||||||
224 | $this->beginPage(); |
||||||
225 | $this->head(); |
||||||
226 | $this->beginBody(); |
||||||
227 | echo $this->renderFile($viewFile, $params, $context); |
||||||
228 | $this->endBody(); |
||||||
229 | $this->endPage(true); |
||||||
230 | |||||||
231 | return ob_get_clean(); |
||||||
232 | } |
||||||
233 | |||||||
234 | /** |
||||||
235 | * Registers the asset manager being used by this view object. |
||||||
236 | * @return \yii\web\AssetManager the asset manager. Defaults to the "assetManager" application component. |
||||||
237 | */ |
||||||
238 | 59 | public function getAssetManager() |
|||||
239 | { |
||||||
240 | 59 | return $this->_assetManager ?: Yii::$app->getAssetManager(); |
|||||
241 | } |
||||||
242 | |||||||
243 | /** |
||||||
244 | * Sets the asset manager. |
||||||
245 | * @param \yii\web\AssetManager $value the asset manager |
||||||
246 | */ |
||||||
247 | 82 | public function setAssetManager($value) |
|||||
248 | { |
||||||
249 | 82 | $this->_assetManager = $value; |
|||||
250 | } |
||||||
251 | |||||||
252 | /** |
||||||
253 | * Clears up the registered meta tags, link tags, css/js scripts and files. |
||||||
254 | */ |
||||||
255 | 58 | public function clear() |
|||||
256 | { |
||||||
257 | 58 | $this->metaTags = []; |
|||||
258 | 58 | $this->linkTags = []; |
|||||
259 | 58 | $this->css = []; |
|||||
260 | 58 | $this->cssFiles = []; |
|||||
261 | 58 | $this->js = []; |
|||||
262 | 58 | $this->jsFiles = []; |
|||||
263 | 58 | $this->assetBundles = []; |
|||||
264 | } |
||||||
265 | |||||||
266 | /** |
||||||
267 | * Registers all files provided by an asset bundle including depending bundles files. |
||||||
268 | * Removes a bundle from [[assetBundles]] once files are registered. |
||||||
269 | * @param string $name name of the bundle to register |
||||||
270 | */ |
||||||
271 | 15 | protected function registerAssetFiles($name) |
|||||
272 | { |
||||||
273 | 15 | if (!isset($this->assetBundles[$name])) { |
|||||
274 | 12 | return; |
|||||
275 | } |
||||||
276 | 15 | $bundle = $this->assetBundles[$name]; |
|||||
277 | 15 | if ($bundle) { |
|||||
0 ignored issues
–
show
introduced
by
![]() |
|||||||
278 | 15 | foreach ($bundle->depends as $dep) { |
|||||
279 | 12 | $this->registerAssetFiles($dep); |
|||||
280 | } |
||||||
281 | 15 | $bundle->registerAssetFiles($this); |
|||||
282 | } |
||||||
283 | 15 | unset($this->assetBundles[$name]); |
|||||
284 | } |
||||||
285 | |||||||
286 | /** |
||||||
287 | * Registers the named asset bundle. |
||||||
288 | * All dependent asset bundles will be registered. |
||||||
289 | * @param string $name the class name of the asset bundle (without the leading backslash) |
||||||
290 | * @param int|null $position if set, this forces a minimum position for javascript files. |
||||||
291 | * This will adjust depending assets javascript file position or fail if requirement can not be met. |
||||||
292 | * If this is null, asset bundles position settings will not be changed. |
||||||
293 | * See [[registerJsFile]] for more details on javascript position. |
||||||
294 | * @return AssetBundle the registered asset bundle instance |
||||||
295 | * @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected |
||||||
296 | */ |
||||||
297 | 35 | public function registerAssetBundle($name, $position = null) |
|||||
298 | { |
||||||
299 | 35 | if (!isset($this->assetBundles[$name])) { |
|||||
300 | 34 | $am = $this->getAssetManager(); |
|||||
301 | 34 | $bundle = $am->getBundle($name); |
|||||
302 | 34 | $this->assetBundles[$name] = false; |
|||||
303 | // register dependencies |
||||||
304 | 34 | $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null; |
|||||
305 | 34 | foreach ($bundle->depends as $dep) { |
|||||
306 | 24 | $this->registerAssetBundle($dep, $pos); |
|||||
307 | } |
||||||
308 | 33 | $this->assetBundles[$name] = $bundle; |
|||||
309 | 19 | } elseif ($this->assetBundles[$name] === false) { |
|||||
0 ignored issues
–
show
|
|||||||
310 | 1 | throw new InvalidConfigException("A circular dependency is detected for bundle '$name'."); |
|||||
311 | } else { |
||||||
312 | 18 | $bundle = $this->assetBundles[$name]; |
|||||
313 | } |
||||||
314 | |||||||
315 | 34 | if ($position !== null) { |
|||||
316 | 12 | $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null; |
|||||
317 | 12 | if ($pos === null) { |
|||||
318 | 12 | $bundle->jsOptions['position'] = $pos = $position; |
|||||
319 | 6 | } elseif ($pos > $position) { |
|||||
320 | 6 | throw new InvalidConfigException("An asset bundle that depends on '$name' has a higher javascript file position configured than '$name'."); |
|||||
321 | } |
||||||
322 | // update position for all dependencies |
||||||
323 | 12 | foreach ($bundle->depends as $dep) { |
|||||
324 | 6 | $this->registerAssetBundle($dep, $pos); |
|||||
325 | } |
||||||
326 | } |
||||||
327 | |||||||
328 | 34 | return $bundle; |
|||||
329 | } |
||||||
330 | |||||||
331 | /** |
||||||
332 | * Registers a meta tag. |
||||||
333 | * |
||||||
334 | * For example, a description meta tag can be added like the following: |
||||||
335 | * |
||||||
336 | * ```php |
||||||
337 | * $view->registerMetaTag([ |
||||||
338 | * 'name' => 'description', |
||||||
339 | * 'content' => 'This website is about funny raccoons.' |
||||||
340 | * ]); |
||||||
341 | * ``` |
||||||
342 | * |
||||||
343 | * will result in the meta tag `<meta name="description" content="This website is about funny raccoons.">`. |
||||||
344 | * |
||||||
345 | * @param array $options the HTML attributes for the meta tag. |
||||||
346 | * @param string|null $key the key that identifies the meta tag. If two meta tags are registered |
||||||
347 | * with the same key, the latter will overwrite the former. If this is null, the new meta tag |
||||||
348 | * will be appended to the existing ones. |
||||||
349 | */ |
||||||
350 | public function registerMetaTag($options, $key = null) |
||||||
351 | { |
||||||
352 | if ($key === null) { |
||||||
353 | $this->metaTags[] = Html::tag('meta', '', $options); |
||||||
354 | } else { |
||||||
355 | $this->metaTags[$key] = Html::tag('meta', '', $options); |
||||||
356 | } |
||||||
357 | } |
||||||
358 | |||||||
359 | /** |
||||||
360 | * Registers CSRF meta tags. |
||||||
361 | * They are rendered dynamically to retrieve a new CSRF token for each request. |
||||||
362 | * |
||||||
363 | * ```php |
||||||
364 | * $view->registerCsrfMetaTags(); |
||||||
365 | * ``` |
||||||
366 | * |
||||||
367 | * The above code will result in `<meta name="csrf-param" content="[yii\web\Request::$csrfParam]">` |
||||||
368 | * and `<meta name="csrf-token" content="tTNpWKpdy-bx8ZmIq9R72...K1y8IP3XGkzZA==">` added to the page. |
||||||
369 | * |
||||||
370 | * Note: Hidden CSRF input of ActiveForm will be automatically refreshed by calling `window.yii.refreshCsrfToken()` |
||||||
371 | * from `yii.js`. |
||||||
372 | * |
||||||
373 | * @since 2.0.13 |
||||||
374 | */ |
||||||
375 | 1 | public function registerCsrfMetaTags() |
|||||
376 | { |
||||||
377 | 1 | $this->metaTags['csrf_meta_tags'] = $this->renderDynamic('return yii\helpers\Html::csrfMetaTags();'); |
|||||
378 | } |
||||||
379 | |||||||
380 | /** |
||||||
381 | * Registers a link tag. |
||||||
382 | * |
||||||
383 | * For example, a link tag for a custom [favicon](https://www.w3.org/2005/10/howto-favicon) |
||||||
384 | * can be added like the following: |
||||||
385 | * |
||||||
386 | * ```php |
||||||
387 | * $view->registerLinkTag(['rel' => 'icon', 'type' => 'image/png', 'href' => '/myicon.png']); |
||||||
388 | * ``` |
||||||
389 | * |
||||||
390 | * which will result in the following HTML: `<link rel="icon" type="image/png" href="/myicon.png">`. |
||||||
391 | * |
||||||
392 | * **Note:** To register link tags for CSS stylesheets, use [[registerCssFile()]] instead, which |
||||||
393 | * has more options for this kind of link tag. |
||||||
394 | * |
||||||
395 | * @param array $options the HTML attributes for the link tag. |
||||||
396 | * @param string|null $key the key that identifies the link tag. If two link tags are registered |
||||||
397 | * with the same key, the latter will overwrite the former. If this is null, the new link tag |
||||||
398 | * will be appended to the existing ones. |
||||||
399 | */ |
||||||
400 | public function registerLinkTag($options, $key = null) |
||||||
401 | { |
||||||
402 | if ($key === null) { |
||||||
403 | $this->linkTags[] = Html::tag('link', '', $options); |
||||||
404 | } else { |
||||||
405 | $this->linkTags[$key] = Html::tag('link', '', $options); |
||||||
406 | } |
||||||
407 | } |
||||||
408 | |||||||
409 | /** |
||||||
410 | * Registers a CSS code block. |
||||||
411 | * @param string $css the content of the CSS code block to be registered |
||||||
412 | * @param array $options the HTML attributes for the `<style>`-tag. |
||||||
413 | * @param string|null $key the key that identifies the CSS code block. If null, it will use |
||||||
414 | * $css as the key. If two CSS code blocks are registered with the same key, the latter |
||||||
415 | * will overwrite the former. |
||||||
416 | */ |
||||||
417 | public function registerCss($css, $options = [], $key = null) |
||||||
418 | { |
||||||
419 | $key = $key ?: md5($css); |
||||||
420 | $this->css[$key] = Html::style($css, $options); |
||||||
421 | } |
||||||
422 | |||||||
423 | /** |
||||||
424 | * Registers a CSS file. |
||||||
425 | * |
||||||
426 | * This method should be used for simple registration of CSS files. If you want to use features of |
||||||
427 | * [[AssetManager]] like appending timestamps to the URL and file publishing options, use [[AssetBundle]] |
||||||
428 | * and [[registerAssetBundle()]] instead. |
||||||
429 | * |
||||||
430 | * @param string $url the CSS file to be registered. |
||||||
431 | * @param array $options the HTML attributes for the link tag. Please refer to [[Html::cssFile()]] for |
||||||
432 | * the supported options. The following options are specially handled and are not treated as HTML attributes: |
||||||
433 | * |
||||||
434 | * - `depends`: array, specifies the names of the asset bundles that this CSS file depends on. |
||||||
435 | * - `appendTimestamp`: bool whether to append a timestamp to the URL. |
||||||
436 | * |
||||||
437 | * @param string|null $key the key that identifies the CSS script file. If null, it will use |
||||||
438 | * $url as the key. If two CSS files are registered with the same key, the latter |
||||||
439 | * will overwrite the former. |
||||||
440 | * @throws InvalidConfigException |
||||||
441 | */ |
||||||
442 | 20 | public function registerCssFile($url, $options = [], $key = null) |
|||||
443 | { |
||||||
444 | 20 | $this->registerFile('css', $url, $options, $key); |
|||||
445 | } |
||||||
446 | |||||||
447 | /** |
||||||
448 | * Registers a JS code block. |
||||||
449 | * @param string $js the JS code block to be registered |
||||||
450 | * @param int $position the position at which the JS script tag should be inserted |
||||||
451 | * in a page. The possible values are: |
||||||
452 | * |
||||||
453 | * - [[POS_HEAD]]: in the head section |
||||||
454 | * - [[POS_BEGIN]]: at the beginning of the body section |
||||||
455 | * - [[POS_END]]: at the end of the body section |
||||||
456 | * - [[POS_LOAD]]: enclosed within jQuery(window).load(). |
||||||
457 | * Note that by using this position, the method will automatically register the jQuery js file. |
||||||
458 | * - [[POS_READY]]: enclosed within jQuery(document).ready(). This is the default value. |
||||||
459 | * Note that by using this position, the method will automatically register the jQuery js file. |
||||||
460 | * |
||||||
461 | * @param string|null $key the key that identifies the JS code block. If null, it will use |
||||||
462 | * $js as the key. If two JS code blocks are registered with the same key, the latter |
||||||
463 | * will overwrite the former. |
||||||
464 | */ |
||||||
465 | 10 | public function registerJs($js, $position = self::POS_READY, $key = null) |
|||||
466 | { |
||||||
467 | 10 | $key = $key ?: md5($js); |
|||||
468 | 10 | $this->js[$position][$key] = $js; |
|||||
469 | 10 | if ($position === self::POS_READY || $position === self::POS_LOAD) { |
|||||
470 | 8 | JqueryAsset::register($this); |
|||||
471 | } |
||||||
472 | } |
||||||
473 | |||||||
474 | /** |
||||||
475 | * Registers a JS or CSS file. |
||||||
476 | * |
||||||
477 | * @param string $url the JS file to be registered. |
||||||
478 | * @param string $type type (js or css) of the file. |
||||||
479 | * @param array $options the HTML attributes for the script tag. The following options are specially handled |
||||||
480 | * and are not treated as HTML attributes: |
||||||
481 | * |
||||||
482 | * - `depends`: array, specifies the names of the asset bundles that this CSS file depends on. |
||||||
483 | * - `appendTimestamp`: bool whether to append a timestamp to the URL. |
||||||
484 | * |
||||||
485 | * @param string|null $key the key that identifies the JS script file. If null, it will use |
||||||
486 | * $url as the key. If two JS files are registered with the same key at the same position, the latter |
||||||
487 | * will overwrite the former. Note that position option takes precedence, thus files registered with the same key, |
||||||
488 | * but different position option will not override each other. |
||||||
489 | * @throws InvalidConfigException |
||||||
490 | */ |
||||||
491 | 36 | private function registerFile($type, $url, $options = [], $key = null) |
|||||
492 | { |
||||||
493 | 36 | $url = Yii::getAlias($url); |
|||||
494 | 36 | $key = $key ?: $url; |
|||||
495 | 36 | $depends = ArrayHelper::remove($options, 'depends', []); |
|||||
496 | 36 | $originalOptions = $options; |
|||||
497 | 36 | $position = ArrayHelper::remove($options, 'position', self::POS_END); |
|||||
498 | |||||||
499 | try { |
||||||
500 | 36 | $assetManagerAppendTimestamp = $this->getAssetManager()->appendTimestamp; |
|||||
501 | } catch (InvalidConfigException $e) { |
||||||
502 | $depends = null; // the AssetManager is not available |
||||||
503 | $assetManagerAppendTimestamp = false; |
||||||
504 | } |
||||||
505 | 36 | $appendTimestamp = ArrayHelper::remove($options, 'appendTimestamp', $assetManagerAppendTimestamp); |
|||||
506 | |||||||
507 | 36 | if ($this->isPageEnded) { |
|||||
508 | Yii::warning('You\'re trying to register a file after View::endPage() has been called.'); |
||||||
509 | } |
||||||
510 | |||||||
511 | 36 | if (empty($depends)) { |
|||||
512 | // register directly without AssetManager |
||||||
513 | 36 | if ($appendTimestamp && Url::isRelative($url)) { |
|||||
0 ignored issues
–
show
It seems like
$url can also be of type false ; however, parameter $url of yii\helpers\BaseUrl::isRelative() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
514 | 5 | $prefix = Yii::getAlias('@web'); |
|||||
515 | 5 | $prefixLength = strlen($prefix); |
|||||
0 ignored issues
–
show
It seems like
$prefix can also be of type false ; however, parameter $string of strlen() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
516 | 5 | $trimmedUrl = ltrim((substr($url, 0, $prefixLength) === $prefix) ? substr($url, $prefixLength) : $url, '/'); |
|||||
0 ignored issues
–
show
It seems like
$url can also be of type false ; however, parameter $string of substr() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() It seems like
substr($url, 0, $prefixL..., $prefixLength) : $url can also be of type false ; however, parameter $string of ltrim() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
517 | 5 | $timestamp = @filemtime(Yii::getAlias('@webroot/' . $trimmedUrl, false)); |
|||||
0 ignored issues
–
show
It seems like
Yii::getAlias('@webroot/' . $trimmedUrl, false) can also be of type false ; however, parameter $filename of filemtime() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
518 | 5 | if ($timestamp > 0) { |
|||||
519 | 2 | $url = $timestamp ? "$url?v=$timestamp" : $url; |
|||||
520 | } |
||||||
521 | } |
||||||
522 | 36 | if ($type === 'js') { |
|||||
523 | 24 | $this->jsFiles[$position][$key] = Html::jsFile($url, $options); |
|||||
0 ignored issues
–
show
It seems like
$url can also be of type false ; however, parameter $url of yii\helpers\BaseHtml::jsFile() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
524 | } else { |
||||||
525 | 36 | $this->cssFiles[$key] = Html::cssFile($url, $options); |
|||||
0 ignored issues
–
show
It seems like
$url can also be of type false ; however, parameter $url of yii\helpers\BaseHtml::cssFile() does only seem to accept array|string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
526 | } |
||||||
527 | } else { |
||||||
528 | 4 | $this->getAssetManager()->bundles[$key] = Yii::createObject([ |
|||||
529 | 4 | 'class' => AssetBundle::className(), |
|||||
0 ignored issues
–
show
The function
yii\base\BaseObject::className() has been deprecated: since 2.0.14. On PHP >=5.5, use `::class` instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
530 | 4 | 'baseUrl' => '', |
|||||
531 | 4 | 'basePath' => '@webroot', |
|||||
532 | 4 | (string)$type => [ArrayHelper::merge([!Url::isRelative($url) ? $url : ltrim($url, '/')], $originalOptions)], |
|||||
533 | 4 | "{$type}Options" => $options, |
|||||
534 | 4 | 'depends' => (array)$depends, |
|||||
535 | 4 | ]); |
|||||
536 | 4 | $this->registerAssetBundle($key); |
|||||
0 ignored issues
–
show
It seems like
$key can also be of type false ; however, parameter $name of yii\web\View::registerAssetBundle() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
537 | } |
||||||
538 | } |
||||||
539 | |||||||
540 | /** |
||||||
541 | * Registers a JS file. |
||||||
542 | * |
||||||
543 | * This method should be used for simple registration of JS files. If you want to use features of |
||||||
544 | * [[AssetManager]] like appending timestamps to the URL and file publishing options, use [[AssetBundle]] |
||||||
545 | * and [[registerAssetBundle()]] instead. |
||||||
546 | * |
||||||
547 | * @param string $url the JS file to be registered. |
||||||
548 | * @param array $options the HTML attributes for the script tag. The following options are specially handled |
||||||
549 | * and are not treated as HTML attributes: |
||||||
550 | * |
||||||
551 | * - `depends`: array, specifies the names of the asset bundles that this JS file depends on. |
||||||
552 | * - `position`: specifies where the JS script tag should be inserted in a page. The possible values are: |
||||||
553 | * * [[POS_HEAD]]: in the head section |
||||||
554 | * * [[POS_BEGIN]]: at the beginning of the body section |
||||||
555 | * * [[POS_END]]: at the end of the body section. This is the default value. |
||||||
556 | * - `appendTimestamp`: bool whether to append a timestamp to the URL. |
||||||
557 | * |
||||||
558 | * Please refer to [[Html::jsFile()]] for other supported options. |
||||||
559 | * |
||||||
560 | * @param string|null $key the key that identifies the JS script file. If null, it will use |
||||||
561 | * $url as the key. If two JS files are registered with the same key at the same position, the latter |
||||||
562 | * will overwrite the former. Note that position option takes precedence, thus files registered with the same key, |
||||||
563 | * but different position option will not override each other. |
||||||
564 | * @throws InvalidConfigException |
||||||
565 | */ |
||||||
566 | 24 | public function registerJsFile($url, $options = [], $key = null) |
|||||
567 | { |
||||||
568 | 24 | $this->registerFile('js', $url, $options, $key); |
|||||
569 | } |
||||||
570 | |||||||
571 | /** |
||||||
572 | * Registers a JS code block defining a variable. The name of variable will be |
||||||
573 | * used as key, preventing duplicated variable names. |
||||||
574 | * |
||||||
575 | * @param string $name Name of the variable |
||||||
576 | * @param array|string $value Value of the variable |
||||||
577 | * @param int $position the position in a page at which the JavaScript variable should be inserted. |
||||||
578 | * The possible values are: |
||||||
579 | * |
||||||
580 | * - [[POS_HEAD]]: in the head section. This is the default value. |
||||||
581 | * - [[POS_BEGIN]]: at the beginning of the body section. |
||||||
582 | * - [[POS_END]]: at the end of the body section. |
||||||
583 | * - [[POS_LOAD]]: enclosed within jQuery(window).load(). |
||||||
584 | * Note that by using this position, the method will automatically register the jQuery js file. |
||||||
585 | * - [[POS_READY]]: enclosed within jQuery(document).ready(). |
||||||
586 | * Note that by using this position, the method will automatically register the jQuery js file. |
||||||
587 | * |
||||||
588 | * @since 2.0.14 |
||||||
589 | */ |
||||||
590 | 1 | public function registerJsVar($name, $value, $position = self::POS_HEAD) |
|||||
591 | { |
||||||
592 | 1 | $js = sprintf('var %s = %s;', $name, \yii\helpers\Json::htmlEncode($value)); |
|||||
593 | 1 | $this->registerJs($js, $position, $name); |
|||||
594 | } |
||||||
595 | |||||||
596 | /** |
||||||
597 | * Renders the content to be inserted in the head section. |
||||||
598 | * The content is rendered using the registered meta tags, link tags, CSS/JS code blocks and files. |
||||||
599 | * @return string the rendered content |
||||||
600 | */ |
||||||
601 | 56 | protected function renderHeadHtml() |
|||||
602 | { |
||||||
603 | 56 | $lines = []; |
|||||
604 | 56 | if (!empty($this->metaTags)) { |
|||||
605 | 1 | $lines[] = implode("\n", $this->metaTags); |
|||||
606 | } |
||||||
607 | |||||||
608 | 56 | if (!empty($this->linkTags)) { |
|||||
609 | $lines[] = implode("\n", $this->linkTags); |
||||||
610 | } |
||||||
611 | 56 | if (!empty($this->cssFiles)) { |
|||||
612 | 20 | $lines[] = implode("\n", $this->cssFiles); |
|||||
613 | } |
||||||
614 | 56 | if (!empty($this->css)) { |
|||||
615 | $lines[] = implode("\n", $this->css); |
||||||
616 | } |
||||||
617 | 56 | if (!empty($this->jsFiles[self::POS_HEAD])) { |
|||||
618 | 3 | $lines[] = implode("\n", $this->jsFiles[self::POS_HEAD]); |
|||||
619 | } |
||||||
620 | 56 | if (!empty($this->js[self::POS_HEAD])) { |
|||||
621 | 1 | $lines[] = Html::script(implode("\n", $this->js[self::POS_HEAD])); |
|||||
622 | } |
||||||
623 | |||||||
624 | 56 | return empty($lines) ? '' : implode("\n", $lines); |
|||||
625 | } |
||||||
626 | |||||||
627 | /** |
||||||
628 | * Renders the content to be inserted at the beginning of the body section. |
||||||
629 | * The content is rendered using the registered JS code blocks and files. |
||||||
630 | * @return string the rendered content |
||||||
631 | */ |
||||||
632 | 56 | protected function renderBodyBeginHtml() |
|||||
633 | { |
||||||
634 | 56 | $lines = []; |
|||||
635 | 56 | if (!empty($this->jsFiles[self::POS_BEGIN])) { |
|||||
636 | 3 | $lines[] = implode("\n", $this->jsFiles[self::POS_BEGIN]); |
|||||
637 | } |
||||||
638 | 56 | if (!empty($this->js[self::POS_BEGIN])) { |
|||||
639 | $lines[] = Html::script(implode("\n", $this->js[self::POS_BEGIN])); |
||||||
640 | } |
||||||
641 | |||||||
642 | 56 | return empty($lines) ? '' : implode("\n", $lines); |
|||||
643 | } |
||||||
644 | |||||||
645 | /** |
||||||
646 | * Renders the content to be inserted at the end of the body section. |
||||||
647 | * The content is rendered using the registered JS code blocks and files. |
||||||
648 | * @param bool $ajaxMode whether the view is rendering in AJAX mode. |
||||||
649 | * If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions |
||||||
650 | * will be rendered at the end of the view like normal scripts. |
||||||
651 | * @return string the rendered content |
||||||
652 | */ |
||||||
653 | 56 | protected function renderBodyEndHtml($ajaxMode) |
|||||
654 | { |
||||||
655 | 56 | $lines = []; |
|||||
656 | |||||||
657 | 56 | if (!empty($this->jsFiles[self::POS_END])) { |
|||||
658 | 19 | $lines[] = implode("\n", $this->jsFiles[self::POS_END]); |
|||||
659 | } |
||||||
660 | |||||||
661 | 56 | if ($ajaxMode) { |
|||||
662 | $scripts = []; |
||||||
663 | if (!empty($this->js[self::POS_END])) { |
||||||
664 | $scripts[] = implode("\n", $this->js[self::POS_END]); |
||||||
665 | } |
||||||
666 | if (!empty($this->js[self::POS_READY])) { |
||||||
667 | $scripts[] = implode("\n", $this->js[self::POS_READY]); |
||||||
668 | } |
||||||
669 | if (!empty($this->js[self::POS_LOAD])) { |
||||||
670 | $scripts[] = implode("\n", $this->js[self::POS_LOAD]); |
||||||
671 | } |
||||||
672 | if (!empty($scripts)) { |
||||||
673 | $lines[] = Html::script(implode("\n", $scripts)); |
||||||
674 | } |
||||||
675 | } else { |
||||||
676 | 56 | if (!empty($this->js[self::POS_END])) { |
|||||
677 | $lines[] = Html::script(implode("\n", $this->js[self::POS_END])); |
||||||
678 | } |
||||||
679 | 56 | if (!empty($this->js[self::POS_READY])) { |
|||||
680 | $js = "jQuery(function ($) {\n" . implode("\n", $this->js[self::POS_READY]) . "\n});"; |
||||||
681 | $lines[] = Html::script($js); |
||||||
682 | } |
||||||
683 | 56 | if (!empty($this->js[self::POS_LOAD])) { |
|||||
684 | $js = "jQuery(window).on('load', function () {\n" . implode("\n", $this->js[self::POS_LOAD]) . "\n});"; |
||||||
685 | $lines[] = Html::script($js); |
||||||
686 | } |
||||||
687 | } |
||||||
688 | |||||||
689 | 56 | return empty($lines) ? '' : implode("\n", $lines); |
|||||
690 | } |
||||||
691 | } |
||||||
692 |