@@ -119,6 +119,29 @@ class View implements RendererInterface
119119 */
120120 protected $ viewsCount = 0 ;
121121
122+ /**
123+ * The name of the layout being used, if any.
124+ * Set by the `extend` method used within views.
125+ *
126+ * @var string
127+ */
128+ protected $ layout ;
129+
130+ /**
131+ * Holds the sections and their data.
132+ *
133+ * @var array
134+ */
135+ protected $ sections = [];
136+
137+ /**
138+ * The name of the current section being rendered,
139+ * if any.
140+ *
141+ * @var string
142+ */
143+ protected $ currentSection ;
144+
122145 //--------------------------------------------------------------------
123146
124147 /**
@@ -211,6 +234,16 @@ public function render(string $view, array $options = null, $saveData = null): s
211234 $ output = ob_get_contents ();
212235 @ob_end_clean ();
213236
237+ // When using layouts, the data has already been stored
238+ // in $this->sections, and no other valid output
239+ // is allowed in $output so we'll overwrite it.
240+ if (! is_null ($ this ->layout ))
241+ {
242+ $ layoutView = $ this ->layout ;
243+ $ this ->layout = null ;
244+ $ output = $ this ->render ($ layoutView , $ options , $ saveData );
245+ }
246+
214247 $ this ->logPerformance ($ this ->renderVars ['start ' ], microtime (true ), $ this ->renderVars ['view ' ]);
215248
216249 if (CI_DEBUG && (! isset ($ options ['debug ' ]) || $ options ['debug ' ] === true ))
@@ -376,6 +409,82 @@ public function getData()
376409
377410 //--------------------------------------------------------------------
378411
412+ /**
413+ * Specifies that the current view should extend an existing layout.
414+ *
415+ * @param string $layout
416+ *
417+ * @return $this
418+ */
419+ public function extend (string $ layout )
420+ {
421+ $ this ->layout = $ layout ;
422+ }
423+
424+ //--------------------------------------------------------------------
425+
426+ /**
427+ * Starts holds content for a section within the layout.
428+ *
429+ * @param string $name
430+ */
431+ public function section (string $ name )
432+ {
433+ $ this ->currentSection = $ name ;
434+
435+ ob_start ();
436+ }
437+
438+ //--------------------------------------------------------------------
439+
440+ /**
441+ *
442+ *
443+ * @throws \Zend\Escaper\Exception\RuntimeException
444+ */
445+ public function endSection ()
446+ {
447+ $ contents = ob_get_clean ();
448+
449+ if (empty ($ this ->currentSection ))
450+ {
451+ throw new \RuntimeException ('View themes, no current section. ' );
452+ }
453+
454+ // Ensure an array exists so we can store multiple entries for this.
455+ if (! array_key_exists ($ this ->currentSection , $ this ->sections ))
456+ {
457+ $ this ->sections [$ this ->currentSection ] = [];
458+ }
459+ $ this ->sections [$ this ->currentSection ][] = $ contents ;
460+
461+ $ this ->currentSection = null ;
462+ }
463+
464+ //--------------------------------------------------------------------
465+
466+ /**
467+ * Renders a section's contents.
468+ *
469+ * @param string $sectionName
470+ */
471+ public function renderSection (string $ sectionName )
472+ {
473+ if (! isset ($ this ->sections [$ sectionName ]))
474+ {
475+ echo '' ;
476+
477+ return ;
478+ }
479+
480+ foreach ($ this ->sections [$ sectionName ] as $ contents )
481+ {
482+ echo $ contents ;
483+ }
484+ }
485+
486+ //--------------------------------------------------------------------
487+
379488 /**
380489 * Returns the performance data that might have been collected
381490 * during the execution. Used primarily in the Debug Toolbar.
0 commit comments