Issues (910)

framework/base/View.php (9 issues)

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\base;
9
10
use Yii;
11
use yii\helpers\FileHelper;
12
use yii\widgets\Block;
13
use yii\widgets\ContentDecorator;
14
use yii\widgets\FragmentCache;
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
 * For more details and usage information on View, see the [guide article on views](guide:structure-views).
22
 *
23
 * @property-read DynamicContentAwareInterface[] $dynamicContents Class instances supporting dynamic contents.
24
 * @property-read string|bool $viewFile The view file currently being rendered. False if no view file is being
25
 * rendered.
26
 *
27
 * @author Qiang Xue <[email protected]>
28
 * @since 2.0
29
 */
30
class View extends Component implements DynamicContentAwareInterface
31
{
32
    /**
33
     * @event Event an event that is triggered by [[beginPage()]].
34
     */
35
    const EVENT_BEGIN_PAGE = 'beginPage';
36
    /**
37
     * @event Event an event that is triggered by [[endPage()]].
38
     */
39
    const EVENT_END_PAGE = 'endPage';
40
    /**
41
     * @event ViewEvent an event that is triggered by [[renderFile()]] right before it renders a view file.
42
     */
43
    const EVENT_BEFORE_RENDER = 'beforeRender';
44
    /**
45
     * @event ViewEvent an event that is triggered by [[renderFile()]] right after it renders a view file.
46
     */
47
    const EVENT_AFTER_RENDER = 'afterRender';
48
49
    /**
50
     * @var ViewContextInterface the context under which the [[renderFile()]] method is being invoked.
51
     */
52
    public $context;
53
    /**
54
     * @var array custom parameters that are shared among view templates.
55
     */
56
    public $params = [];
57
    /**
58
     * @var array|null a list of available renderers indexed by their corresponding supported file extensions.
59
     * Each renderer may be a view renderer object or the configuration for creating the renderer object.
60
     * For example, the following configuration enables both Smarty and Twig view renderers:
61
     *
62
     * ```php
63
     * [
64
     *     'tpl' => ['class' => 'yii\smarty\ViewRenderer'],
65
     *     'twig' => ['class' => 'yii\twig\ViewRenderer'],
66
     * ]
67
     * ```
68
     *
69
     * If no renderer is available for the given view file, the view file will be treated as a normal PHP
70
     * and rendered via [[renderPhpFile()]].
71
     */
72
    public $renderers;
73
    /**
74
     * @var string the default view file extension. This will be appended to view file names if they don't have file extensions.
75
     */
76
    public $defaultExtension = 'php';
77
    /**
78
     * @var Theme|array|string|null the theme object or the configuration for creating the theme object.
79
     * If not set, it means theming is not enabled.
80
     */
81
    public $theme;
82
    /**
83
     * @var array a list of named output blocks. The keys are the block names and the values
84
     * are the corresponding block content. You can call [[beginBlock()]] and [[endBlock()]]
85
     * to capture small fragments of a view. They can be later accessed somewhere else
86
     * through this property.
87
     */
88
    public $blocks;
89
    /**
90
     * @var array|DynamicContentAwareInterface[] a list of currently active dynamic content class instances.
91
     * This property is used internally to implement the dynamic content caching feature. Do not modify it directly.
92
     * @internal
93
     * @deprecated Since 2.0.14. Do not use this property directly. Use methods [[getDynamicContents()]],
94
     * [[pushDynamicContent()]], [[popDynamicContent()]] instead.
95
     */
96
    public $cacheStack = [];
97
    /**
98
     * @var array a list of placeholders for embedding dynamic contents. This property
99
     * is used internally to implement the content caching feature. Do not modify it directly.
100
     * @internal
101
     * @deprecated Since 2.0.14. Do not use this property directly. Use methods [[getDynamicPlaceholders()]],
102
     * [[setDynamicPlaceholders()]], [[addDynamicPlaceholder()]] instead.
103
     */
104
    public $dynamicPlaceholders = [];
105
106
    /**
107
     * @var array the view files currently being rendered. There may be multiple view files being
108
     * rendered at a moment because one view may be rendered within another.
109
     */
110
    private $_viewFiles = [];
111
112
113
    /**
114
     * Initializes the view component.
115
     */
116 249
    public function init()
117
    {
118 249
        parent::init();
119 249
        if (is_array($this->theme)) {
120
            if (!isset($this->theme['class'])) {
121
                $this->theme['class'] = 'yii\base\Theme';
122
            }
123
            $this->theme = Yii::createObject($this->theme);
124 249
        } elseif (is_string($this->theme)) {
125
            $this->theme = Yii::createObject($this->theme);
126
        }
127
    }
128
129
    /**
130
     * Renders a view.
131
     *
132
     * The view to be rendered can be specified in one of the following formats:
133
     *
134
     * - [path alias](guide:concept-aliases) (e.g. "@app/views/site/index");
135
     * - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
136
     *   The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
137
     * - absolute path within current module (e.g. "/site/index"): the view name starts with a single slash.
138
     *   The actual view file will be looked for under the [[Module::viewPath|view path]] of the [[Controller::module|current module]].
139
     * - relative view (e.g. "index"): the view name does not start with `@` or `/`. The corresponding view file will be
140
     *   looked for under the [[ViewContextInterface::getViewPath()|view path]] of the view `$context`.
141
     *   If `$context` is not given, it will be looked for under the directory containing the view currently
142
     *   being rendered (i.e., this happens when rendering a view within another view).
143
     *
144
     * @param string $view the view name.
145
     * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
146
     * @param object|null $context the context to be assigned to the view and can later be accessed via [[context]]
147
     * in the view. If the context implements [[ViewContextInterface]], it may also be used to locate
148
     * the view file corresponding to a relative view name.
149
     * @return string the rendering result
150
     * @throws ViewNotFoundException if the view file does not exist.
151
     * @throws InvalidCallException if the view cannot be resolved.
152
     * @see renderFile()
153
     */
154 115
    public function render($view, $params = [], $context = null)
155
    {
156 115
        $viewFile = $this->findViewFile($view, $context);
157 115
        return $this->renderFile($viewFile, $params, $context);
158
    }
159
160
    /**
161
     * Finds the view file based on the given view name.
162
     * @param string $view the view name or the [path alias](guide:concept-aliases) of the view file. Please refer to [[render()]]
163
     * on how to specify this parameter.
164
     * @param object|null $context the context to be assigned to the view and can later be accessed via [[context]]
165
     * in the view. If the context implements [[ViewContextInterface]], it may also be used to locate
166
     * the view file corresponding to a relative view name.
167
     * @return string the view file path. Note that the file may not exist.
168
     * @throws InvalidCallException if a relative view name is given while there is no active context to
169
     * determine the corresponding view file.
170
     */
171 115
    protected function findViewFile($view, $context = null)
172
    {
173 115
        if (strncmp($view, '@', 1) === 0) {
174
            // e.g. "@app/views/main"
175 29
            $file = Yii::getAlias($view);
176 87
        } elseif (strncmp($view, '//', 2) === 0) {
177
            // e.g. "//layouts/main"
178
            $file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
179 87
        } elseif (strncmp($view, '/', 1) === 0) {
180
            // e.g. "/site/index"
181
            if (Yii::$app->controller !== null) {
182
                $file = Yii::$app->controller->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
183
            } else {
184
                throw new InvalidCallException("Unable to locate view file for view '$view': no active controller.");
185
            }
186 87
        } elseif ($context instanceof ViewContextInterface) {
187 6
            $file = $context->getViewPath() . DIRECTORY_SEPARATOR . $view;
188 81
        } elseif (($currentViewFile = $this->getRequestedViewFile()) !== false) {
189 81
            $file = dirname($currentViewFile) . DIRECTORY_SEPARATOR . $view;
190
        } else {
191
            throw new InvalidCallException("Unable to resolve view file for view '$view': no active view context.");
192
        }
193
194 115
        if (pathinfo($file, PATHINFO_EXTENSION) !== '') {
195 27
            return $file;
196
        }
197 88
        $path = $file . '.' . $this->defaultExtension;
198 88
        if ($this->defaultExtension !== 'php' && !is_file($path)) {
199
            $path = $file . '.php';
200
        }
201
202 88
        return $path;
203
    }
204
205
    /**
206
     * Renders a view file.
207
     *
208
     * If [[theme]] is enabled (not null), it will try to render the themed version of the view file as long
209
     * as it is available.
210
     *
211
     * The method will call [[FileHelper::localize()]] to localize the view file.
212
     *
213
     * If [[renderers|renderer]] is enabled (not null), the method will use it to render the view file.
214
     * Otherwise, it will simply include the view file as a normal PHP file, capture its output and
215
     * return it as a string.
216
     *
217
     * @param string $viewFile the view file. This can be either an absolute file path or an alias of it.
218
     * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
219
     * @param object|null $context the context that the view should use for rendering the view. If null,
220
     * existing [[context]] will be used.
221
     * @return string the rendering result
222
     * @throws ViewNotFoundException if the view file does not exist
223
     */
224 157
    public function renderFile($viewFile, $params = [], $context = null)
225
    {
226 157
        $viewFile = $requestedFile = Yii::getAlias($viewFile);
227
228 157
        if ($this->theme !== null) {
229 1
            $viewFile = $this->theme->applyTo($viewFile);
230
        }
231 157
        if (is_file($viewFile)) {
232 156
            $viewFile = FileHelper::localize($viewFile);
233
        } else {
234 2
            throw new ViewNotFoundException("The view file does not exist: $viewFile");
235
        }
236
237 156
        $oldContext = $this->context;
238 156
        if ($context !== null) {
239 102
            $this->context = $context;
240
        }
241 156
        $output = '';
242 156
        $this->_viewFiles[] = [
243 156
            'resolved' => $viewFile,
244 156
            'requested' => $requestedFile
245 156
        ];
246
247 156
        if ($this->beforeRender($viewFile, $params)) {
248 156
            Yii::debug("Rendering view file: $viewFile", __METHOD__);
249 156
            $ext = pathinfo($viewFile, PATHINFO_EXTENSION);
250 156
            if (isset($this->renderers[$ext])) {
251
                if (is_array($this->renderers[$ext]) || is_string($this->renderers[$ext])) {
252
                    $this->renderers[$ext] = Yii::createObject($this->renderers[$ext]);
253
                }
254
                /* @var $renderer ViewRenderer */
255
                $renderer = $this->renderers[$ext];
256
                $output = $renderer->render($this, $viewFile, $params);
257
            } else {
258 156
                $output = $this->renderPhpFile($viewFile, $params);
259
            }
260 156
            $this->afterRender($viewFile, $params, $output);
261
        }
262
263 156
        array_pop($this->_viewFiles);
264 156
        $this->context = $oldContext;
265
266 156
        return $output;
267
    }
268
269
    /**
270
     * @return string|bool the view file currently being rendered. False if no view file is being rendered.
271
     */
272
    public function getViewFile()
273
    {
274
        return empty($this->_viewFiles) ? false : end($this->_viewFiles)['resolved'];
275
    }
276
277
    /**
278
     * @return string|bool the requested view currently being rendered. False if no view file is being rendered.
279
     * @since 2.0.16
280
     */
281 81
    protected function getRequestedViewFile()
282
    {
283 81
        return empty($this->_viewFiles) ? false : end($this->_viewFiles)['requested'];
284
    }
285
286
    /**
287
     * This method is invoked right before [[renderFile()]] renders a view file.
288
     * The default implementation will trigger the [[EVENT_BEFORE_RENDER]] event.
289
     * If you override this method, make sure you call the parent implementation first.
290
     * @param string $viewFile the view file to be rendered.
291
     * @param array $params the parameter array passed to the [[render()]] method.
292
     * @return bool whether to continue rendering the view file.
293
     */
294 156
    public function beforeRender($viewFile, $params)
295
    {
296 156
        $event = new ViewEvent([
297 156
            'viewFile' => $viewFile,
298 156
            'params' => $params,
299 156
        ]);
300 156
        $this->trigger(self::EVENT_BEFORE_RENDER, $event);
301
302 156
        return $event->isValid;
303
    }
304
305
    /**
306
     * This method is invoked right after [[renderFile()]] renders a view file.
307
     * The default implementation will trigger the [[EVENT_AFTER_RENDER]] event.
308
     * If you override this method, make sure you call the parent implementation first.
309
     * @param string $viewFile the view file being rendered.
310
     * @param array $params the parameter array passed to the [[render()]] method.
311
     * @param string $output the rendering result of the view file. Updates to this parameter
312
     * will be passed back and returned by [[renderFile()]].
313
     */
314 157
    public function afterRender($viewFile, $params, &$output)
315
    {
316 157
        if ($this->hasEventHandlers(self::EVENT_AFTER_RENDER)) {
317 1
            $event = new ViewEvent([
318 1
                'viewFile' => $viewFile,
319 1
                'params' => $params,
320 1
            ]);
321 1
            $event->output =& $output;
322
323 1
            $this->trigger(self::EVENT_AFTER_RENDER, $event);
324
        }
325
    }
326
327
    /**
328
     * Renders a view file as a PHP script.
329
     *
330
     * This method treats the view file as a PHP script and includes the file.
331
     * It extracts the given parameters and makes them available in the view file.
332
     * The method captures the output of the included view file and returns it as a string.
333
     *
334
     * This method should mainly be called by view renderer or [[renderFile()]].
335
     *
336
     * @param string $_file_ the view file.
337
     * @param array $_params_ the parameters (name-value pairs) that will be extracted and made available in the view file.
338
     * @return string the rendering result
339
     * @throws \Throwable
340
     */
341 156
    public function renderPhpFile($_file_, $_params_ = [])
342
    {
343 156
        $_obInitialLevel_ = ob_get_level();
344 156
        ob_start();
345 156
        ob_implicit_flush(false);
346 156
        extract($_params_, EXTR_OVERWRITE);
347
        try {
348 156
            require $_file_;
349 156
            return ob_get_clean();
350 1
        } catch (\Exception $e) {
351 1
            while (ob_get_level() > $_obInitialLevel_) {
352 1
                if (!@ob_end_clean()) {
353
                    ob_clean();
354
                }
355
            }
356 1
            throw $e;
357
        } catch (\Throwable $e) {
358
            while (ob_get_level() > $_obInitialLevel_) {
359
                if (!@ob_end_clean()) {
360
                    ob_clean();
361
                }
362
            }
363
            throw $e;
364
        }
365
    }
366
367
    /**
368
     * Renders dynamic content returned by the given PHP statements.
369
     * This method is mainly used together with content caching (fragment caching and page caching)
370
     * when some portions of the content (called *dynamic content*) should not be cached.
371
     * The dynamic content must be returned by some PHP statements.
372
     * @param string $statements the PHP statements for generating the dynamic content.
373
     * @return string the placeholder of the dynamic content, or the dynamic content if there is no
374
     * active content cache currently.
375
     *
376
     * Note that most methods that indirectly modify layout such as registerJS() or registerJSFile() do not
377
     * work with dynamic rendering.
378
     *
379
     * @see https://github.com/yiisoft/yii2/issues/17673
380
     */
381 19
    public function renderDynamic($statements)
382
    {
383 19
        if (!empty($this->cacheStack)) {
0 ignored issues
show
Deprecated Code introduced by
The property yii\base\View::$cacheStack has been deprecated: Since 2.0.14. Do not use this property directly. Use methods [[getDynamicContents()]], [[pushDynamicContent()]], [[popDynamicContent()]] instead. ( Ignorable by Annotation )

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

383
        if (!empty(/** @scrutinizer ignore-deprecated */ $this->cacheStack)) {

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
384 17
            $n = count($this->dynamicPlaceholders);
0 ignored issues
show
Deprecated Code introduced by
The property yii\base\View::$dynamicPlaceholders has been deprecated: Since 2.0.14. Do not use this property directly. Use methods [[getDynamicPlaceholders()]], [[setDynamicPlaceholders()]], [[addDynamicPlaceholder()]] instead. ( Ignorable by Annotation )

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

384
            $n = count(/** @scrutinizer ignore-deprecated */ $this->dynamicPlaceholders);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
385 17
            $placeholder = "<![CDATA[YII-DYNAMIC-$n]]>";
386 17
            $this->addDynamicPlaceholder($placeholder, $statements);
387
388 17
            return $placeholder;
389
        }
390
391 2
        return $this->evaluateDynamicContent($statements);
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     */
397
    public function getDynamicPlaceholders()
398
    {
399
        return $this->dynamicPlaceholders;
0 ignored issues
show
Deprecated Code introduced by
The property yii\base\View::$dynamicPlaceholders has been deprecated: Since 2.0.14. Do not use this property directly. Use methods [[getDynamicPlaceholders()]], [[setDynamicPlaceholders()]], [[addDynamicPlaceholder()]] instead. ( Ignorable by Annotation )

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

399
        return /** @scrutinizer ignore-deprecated */ $this->dynamicPlaceholders;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
400
    }
401
402
    /**
403
     * {@inheritdoc}
404
     */
405
    public function setDynamicPlaceholders($placeholders)
406
    {
407
        $this->dynamicPlaceholders = $placeholders;
0 ignored issues
show
Deprecated Code introduced by
The property yii\base\View::$dynamicPlaceholders has been deprecated: Since 2.0.14. Do not use this property directly. Use methods [[getDynamicPlaceholders()]], [[setDynamicPlaceholders()]], [[addDynamicPlaceholder()]] instead. ( Ignorable by Annotation )

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

407
        /** @scrutinizer ignore-deprecated */ $this->dynamicPlaceholders = $placeholders;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
408
    }
409
410
    /**
411
     * {@inheritdoc}
412
     */
413 17
    public function addDynamicPlaceholder($placeholder, $statements)
414
    {
415 17
        foreach ($this->cacheStack as $cache) {
0 ignored issues
show
Deprecated Code introduced by
The property yii\base\View::$cacheStack has been deprecated: Since 2.0.14. Do not use this property directly. Use methods [[getDynamicContents()]], [[pushDynamicContent()]], [[popDynamicContent()]] instead. ( Ignorable by Annotation )

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

415
        foreach (/** @scrutinizer ignore-deprecated */ $this->cacheStack as $cache) {

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
416 17
            if ($cache instanceof DynamicContentAwareInterface) {
417 17
                $cache->addDynamicPlaceholder($placeholder, $statements);
418
            } else {
419
                // TODO: Remove in 2.1
420
                $cache->dynamicPlaceholders[$placeholder] = $statements;
421
            }
422
        }
423 17
        $this->dynamicPlaceholders[$placeholder] = $statements;
0 ignored issues
show
Deprecated Code introduced by
The property yii\base\View::$dynamicPlaceholders has been deprecated: Since 2.0.14. Do not use this property directly. Use methods [[getDynamicPlaceholders()]], [[setDynamicPlaceholders()]], [[addDynamicPlaceholder()]] instead. ( Ignorable by Annotation )

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

423
        /** @scrutinizer ignore-deprecated */ $this->dynamicPlaceholders[$placeholder] = $statements;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
424
    }
425
426
    /**
427
     * Evaluates the given PHP statements.
428
     * This method is mainly used internally to implement dynamic content feature.
429
     * @param string $statements the PHP statements to be evaluated.
430
     * @return mixed the return value of the PHP statements.
431
     */
432 19
    public function evaluateDynamicContent($statements)
433
    {
434 19
        return eval($statements);
435
    }
436
437
    /**
438
     * Returns a list of currently active dynamic content class instances.
439
     * @return DynamicContentAwareInterface[] class instances supporting dynamic contents.
440
     * @since 2.0.14
441
     */
442 17
    public function getDynamicContents()
443
    {
444 17
        return $this->cacheStack;
0 ignored issues
show
Deprecated Code introduced by
The property yii\base\View::$cacheStack has been deprecated: Since 2.0.14. Do not use this property directly. Use methods [[getDynamicContents()]], [[pushDynamicContent()]], [[popDynamicContent()]] instead. ( Ignorable by Annotation )

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

444
        return /** @scrutinizer ignore-deprecated */ $this->cacheStack;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
445
    }
446
447
    /**
448
     * Adds a class instance supporting dynamic contents to the end of a list of currently active
449
     * dynamic content class instances.
450
     * @param DynamicContentAwareInterface $instance class instance supporting dynamic contents.
451
     * @since 2.0.14
452
     */
453 22
    public function pushDynamicContent(DynamicContentAwareInterface $instance)
454
    {
455 22
        $this->cacheStack[] = $instance;
0 ignored issues
show
Deprecated Code introduced by
The property yii\base\View::$cacheStack has been deprecated: Since 2.0.14. Do not use this property directly. Use methods [[getDynamicContents()]], [[pushDynamicContent()]], [[popDynamicContent()]] instead. ( Ignorable by Annotation )

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

455
        /** @scrutinizer ignore-deprecated */ $this->cacheStack[] = $instance;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
456
    }
457
458
    /**
459
     * Removes a last class instance supporting dynamic contents from a list of currently active
460
     * dynamic content class instances.
461
     * @since 2.0.14
462
     */
463 22
    public function popDynamicContent()
464
    {
465 22
        array_pop($this->cacheStack);
0 ignored issues
show
Deprecated Code introduced by
The property yii\base\View::$cacheStack has been deprecated: Since 2.0.14. Do not use this property directly. Use methods [[getDynamicContents()]], [[pushDynamicContent()]], [[popDynamicContent()]] instead. ( Ignorable by Annotation )

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

465
        array_pop(/** @scrutinizer ignore-deprecated */ $this->cacheStack);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
466
    }
467
468
    /**
469
     * Begins recording a block.
470
     *
471
     * This method is a shortcut to beginning [[Block]].
472
     * @param string $id the block ID.
473
     * @param bool $renderInPlace whether to render the block content in place.
474
     * Defaults to false, meaning the captured block will not be displayed.
475
     * @return Block the Block widget instance
476
     */
477
    public function beginBlock($id, $renderInPlace = false)
478
    {
479
        return Block::begin([
480
            'id' => $id,
481
            'renderInPlace' => $renderInPlace,
482
            'view' => $this,
483
        ]);
484
    }
485
486
    /**
487
     * Ends recording a block.
488
     */
489
    public function endBlock()
490
    {
491
        Block::end();
492
    }
493
494
    /**
495
     * Begins the rendering of content that is to be decorated by the specified view.
496
     *
497
     * This method can be used to implement nested layout. For example, a layout can be embedded
498
     * in another layout file specified as '@app/views/layouts/base.php' like the following:
499
     *
500
     * ```php
501
     * <?php $this->beginContent('@app/views/layouts/base.php'); ?>
502
     * //...layout content here...
503
     * <?php $this->endContent(); ?>
504
     * ```
505
     *
506
     * @param string $viewFile the view file that will be used to decorate the content enclosed by this widget.
507
     * This can be specified as either the view file path or [path alias](guide:concept-aliases).
508
     * @param array $params the variables (name => value) to be extracted and made available in the decorative view.
509
     * @return ContentDecorator the ContentDecorator widget instance
510
     * @see ContentDecorator
511
     */
512
    public function beginContent($viewFile, $params = [])
513
    {
514
        return ContentDecorator::begin([
515
            'viewFile' => $viewFile,
516
            'params' => $params,
517
            'view' => $this,
518
        ]);
519
    }
520
521
    /**
522
     * Ends the rendering of content.
523
     */
524
    public function endContent()
525
    {
526
        ContentDecorator::end();
527
    }
528
529
    /**
530
     * Begins fragment caching.
531
     *
532
     * This method will display cached content if it is available.
533
     * If not, it will start caching and would expect an [[endCache()]]
534
     * call to end the cache and save the content into cache.
535
     * A typical usage of fragment caching is as follows,
536
     *
537
     * ```php
538
     * if ($this->beginCache($id)) {
539
     *     // ...generate content here
540
     *     $this->endCache();
541
     * }
542
     * ```
543
     *
544
     * @param string $id a unique ID identifying the fragment to be cached.
545
     * @param array $properties initial property values for [[FragmentCache]]
546
     * @return bool whether you should generate the content for caching.
547
     * False if the cached version is available.
548
     */
549 10
    public function beginCache($id, $properties = [])
550
    {
551 10
        $properties['id'] = $id;
552 10
        $properties['view'] = $this;
553
        /* @var $cache FragmentCache */
554 10
        $cache = FragmentCache::begin($properties);
555 10
        if ($cache->getCachedContent() !== false) {
556 7
            $this->endCache();
557
558 7
            return false;
559
        }
560
561 10
        return true;
562
    }
563
564
    /**
565
     * Ends fragment caching.
566
     */
567 10
    public function endCache()
568
    {
569 10
        FragmentCache::end();
570
    }
571
572
    /**
573
     * Marks the beginning of a page.
574
     */
575 56
    public function beginPage()
576
    {
577 56
        ob_start();
578 56
        ob_implicit_flush(false);
579
580 56
        $this->trigger(self::EVENT_BEGIN_PAGE);
581
    }
582
583
    /**
584
     * Marks the ending of a page.
585
     */
586
    public function endPage()
587
    {
588
        $this->trigger(self::EVENT_END_PAGE);
589
        ob_end_flush();
590
    }
591
}
592