From 131daf401e63ee35bebd65fea118069bb138a4b1 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Thu, 29 Apr 2021 18:46:21 +0800 Subject: [PATCH 1/2] Fix: Nested sections rendering --- system/View/View.php | 30 +++++++++++++--------- tests/system/View/ViewTest.php | 15 ++++++++++- tests/system/View/Views/nested_section.php | 14 ++++++++++ 3 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 tests/system/View/Views/nested_section.php diff --git a/system/View/View.php b/system/View/View.php index 935729393626..9bc3367d2c42 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -120,9 +120,9 @@ class View implements RendererInterface * The name of the current section being rendered, * if any. * - * @var string|null + * @var array */ - protected $currentSection; + protected $sectionStack = []; /** * Constructor @@ -227,7 +227,7 @@ public function render(string $view, array $options = null, bool $saveData = nul // When using layouts, the data has already been stored // in $this->sections, and no other valid output // is allowed in $output so we'll overwrite it. - if (! is_null($this->layout) && empty($this->currentSection)) + if (! is_null($this->layout) && $this->sectionStack === []) { $layoutView = $this->layout; $this->layout = null; @@ -402,35 +402,41 @@ public function extend(string $layout) /** * Starts holds content for a section within the layout. * - * @param string $name + * @param string $name Section name + * + * @return void */ - public function section(string $name) + public function section(string $name): void { - $this->currentSection = $name; + $this->sectionStack[] = $name; ob_start(); } /** + * Captures the last section + * + * @return void * @throws RuntimeException */ - public function endSection() + public function endSection(): void { $contents = ob_get_clean(); - if (empty($this->currentSection)) + if ($this->sectionStack === []) { throw new RuntimeException('View themes, no current section.'); } + $section = array_pop($this->sectionStack); + // Ensure an array exists so we can store multiple entries for this. - if (! array_key_exists($this->currentSection, $this->sections)) + if (! array_key_exists($section, $this->sections)) { - $this->sections[$this->currentSection] = []; + $this->sections[$section] = []; } - $this->sections[$this->currentSection][] = $contents; - $this->currentSection = null; + $this->sections[$section][] = $contents; } /** diff --git a/tests/system/View/ViewTest.php b/tests/system/View/ViewTest.php index 8dd1d4431a38..7d2cf84becbb 100644 --- a/tests/system/View/ViewTest.php +++ b/tests/system/View/ViewTest.php @@ -367,7 +367,7 @@ public function testRenderSaveDataCover() $this->assertEquals(true, $this->getPrivateProperty($view, 'saveData')); } - public function testRenderSaveDataUseAflterSaveDataFalse() + public function testRenderSaveDataUseAfterSaveDataFalse() { $view = new View($this->config, $this->viewsDir, $this->loader); $view->setVar('testString', 'test'); @@ -387,4 +387,17 @@ public function testCachedAutoDiscoverAndRender() // this second renderings should go thru the cache $this->assertStringContainsString($expected, $view->render('Nested/simple', ['cache' => 10])); } + + public function testRenderNestedSections() + { + $view = new View($this->config, $this->viewsDir, $this->loader); + + $view->setVar('testString', 'Hello World'); + + $content = $view->render('nested_section'); + + $this->assertStringContainsString('

First

', $content); + $this->assertStringContainsString('

Second

', $content); + $this->assertStringContainsString('

Third

', $content); + } } diff --git a/tests/system/View/Views/nested_section.php b/tests/system/View/Views/nested_section.php new file mode 100644 index 000000000000..a89e6234ec5c --- /dev/null +++ b/tests/system/View/Views/nested_section.php @@ -0,0 +1,14 @@ +extend('layout'); ?> + +section('content'); ?> +

Second

+ + section('content'); ?> +

First

+ endSection(); ?> + +endSection(); ?> + +section('content'); ?> +

Third

+endSection(); ?> From efb60bf8595d873ba7de5a81d784b2da38ac0790 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Wed, 5 May 2021 12:14:08 +0800 Subject: [PATCH 2/2] Changed UG and applied PR suggestions --- system/View/View.php | 17 +++++++++++++++-- user_guide_src/source/changelogs/v4.1.2.rst | 2 ++ user_guide_src/source/outgoing/view_layouts.rst | 12 ++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/system/View/View.php b/system/View/View.php index 9bc3367d2c42..33efdaa21e13 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -109,6 +109,7 @@ class View implements RendererInterface */ protected $layout; + /** * Holds the sections and their data. * @@ -116,6 +117,15 @@ class View implements RendererInterface */ protected $sections = []; + /** + * The name of the current section being rendered, + * if any. + * + * @var string|null + * @deprecated + */ + protected $currentSection; + /** * The name of the current section being rendered, * if any. @@ -405,9 +415,12 @@ public function extend(string $layout) * @param string $name Section name * * @return void + * */ - public function section(string $name): void + public function section(string $name) { + //Saved to prevent BC. + $this->currentSection = $name; $this->sectionStack[] = $name; ob_start(); @@ -419,7 +432,7 @@ public function section(string $name): void * @return void * @throws RuntimeException */ - public function endSection(): void + public function endSection() { $contents = ob_get_clean(); diff --git a/user_guide_src/source/changelogs/v4.1.2.rst b/user_guide_src/source/changelogs/v4.1.2.rst index 01528d70ef09..4aaf344ec9bc 100644 --- a/user_guide_src/source/changelogs/v4.1.2.rst +++ b/user_guide_src/source/changelogs/v4.1.2.rst @@ -15,6 +15,7 @@ Enhancements: Changes: +- Layouts in views now support nested sections. - ``Response::getCookie`` now returns a ``Cookie`` instance instead of an array of cookie attributes. - ``Response::getCookies`` now returns an array of ``Cookie`` instances instead of array of array of attributes. - To eliminate warnings from modern browsers' consoles, empty samesite values will be defaulted to ``Lax`` on cookie dispatch. @@ -28,6 +29,7 @@ Changes: Deprecations: +- Deprecated ``Codeigniter\View\View::$currentSection`` property. - Language strings and exceptions on invalid cookie samesite are deprecated for the ``CookieException``'s own exception message. - Deprecated `CodeIgniter\Entity` in favor of `CodeIgniter\Entity\Entity` - Deprecated cookie-related properties of ``Response`` in order to use the ``Cookie`` class. diff --git a/user_guide_src/source/outgoing/view_layouts.rst b/user_guide_src/source/outgoing/view_layouts.rst index e93ea9e17e7c..a0e47ab94499 100644 --- a/user_guide_src/source/outgoing/view_layouts.rst +++ b/user_guide_src/source/outgoing/view_layouts.rst @@ -60,6 +60,18 @@ matches the section name exists.:: The ``endSection()`` does not need the section name. It automatically knows which one to close. +Sections can contain nested sections:: + + extend('default') ?> + + section('content') ?> +

Hello World!

+ section('javascript') ?> + let a = 'a'; + endSection() ?> + endSection() ?> + + ****************** Rendering the View ******************