From 576b6cedb378104bdceaf73d0022bb73c4013c02 Mon Sep 17 00:00:00 2001 From: Jonathan Reinink Date: Tue, 27 Dec 2016 14:41:03 -0500 Subject: [PATCH] Add the ability to append content to sections. Closes #135. --- docs/templates/sections.md | 16 +++++++-- example/templates/layout.php | 2 ++ example/templates/profile.php | 8 ++++- src/Template/Template.php | 51 +++++++++++++++++++++++--- tests/Template/TemplateTest.php | 64 +++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 8 deletions(-) diff --git a/docs/templates/sections.md b/docs/templates/sections.md index c59fe855..a5cadcd3 100644 --- a/docs/templates/sections.md +++ b/docs/templates/sections.md @@ -7,11 +7,11 @@ title: Sections Sections ======== -The `start()` and `stop()` functions allow you to build sections (or blocks) of content within your template, and instead of them being rendered directly, they are saved for use elsewhere. For example, in your [layout](/templates/layouts/) template. +The `start()` and `stop` functions allow you to build sections (or blocks) of content within your template, and instead of them being rendered directly, they are saved for use elsewhere. For example, in your [layout](/templates/layouts/) template. ## Creating sections -You define the name of the section in the `start()` function, and end the section with the `stop()` function. +You define the name of the section with the `start()` function. To end a section call the `stop()` function. ~~~ php start('welcome') ?> @@ -22,6 +22,18 @@ You define the name of the section in the `start()` function, and end the sectio stop() ?> ~~~ +## Stacking section content + +By default, when you render a section its content will overwrite any existing content for that section. However, it's possible to append (or stack) the content instead using the `push()` method. This can be useful for specifying any JavaScript libraries required by your child views. + +~~~ php +push('scripts') ?> + +end() ?> +~~~ + +

The end() function is simply an alias of stop(). These functions can be used interchangeably.

+ ## Accessing section content Access rendered section content using the name you assigned in the `start()` method. This variable can be accessed from the current template and layout templates using the `section()` function. diff --git a/example/templates/layout.php b/example/templates/layout.php index b2009bb9..5b5847cf 100644 --- a/example/templates/layout.php +++ b/example/templates/layout.php @@ -6,5 +6,7 @@ section('content')?> +section('scripts')?> + \ No newline at end of file diff --git a/example/templates/profile.php b/example/templates/profile.php index 5592b5b2..0797e463 100644 --- a/example/templates/profile.php +++ b/example/templates/profile.php @@ -3,4 +3,10 @@

User Profile

Hello, e($name)?>!

-insert('sidebar') ?> \ No newline at end of file +insert('sidebar') ?> + +push('scripts') ?> + +end() ?> \ No newline at end of file diff --git a/src/Template/Template.php b/src/Template/Template.php index 12c5037c..0a88c8cf 100644 --- a/src/Template/Template.php +++ b/src/Template/Template.php @@ -36,6 +36,18 @@ class Template */ protected $sections = array(); + /** + * The name of the section currently being rendered. + * @var string + */ + protected $sectionName; + + /** + * Whether the section should be appended or not. + * @var boolean + */ + protected $appendSection; + /** * The name of the template layout. * @var string @@ -178,7 +190,7 @@ public function layout($name, array $data = array()) /** * Start a new section block. - * @param string $name + * @param string $name * @return null */ public function start($name) @@ -189,26 +201,55 @@ public function start($name) ); } - $this->sections[$name] = ''; + if ($this->sectionName) { + throw new LogicException('You cannot nest sections within other sections.'); + } + + $this->sectionName = $name; ob_start(); } + /** + * Start a new append section block. + * @param string $name + * @return null + */ + public function push($name) + { + $this->appendSection = true; + + $this->start($name); + } + /** * Stop the current section block. * @return null */ public function stop() { - if (empty($this->sections)) { + if (is_null($this->sectionName)) { throw new LogicException( 'You must start a section before you can stop it.' ); } - end($this->sections); + if (!isset($this->sections[$this->sectionName])) { + $this->sections[$this->sectionName] = ''; + } + + $this->sections[$this->sectionName] = $this->appendSection ? $this->sections[$this->sectionName] . ob_get_clean() : ob_get_clean(); + $this->sectionName = null; + $this->appendSection = false; + } - $this->sections[key($this->sections)] = ob_get_clean(); + /** + * Alias of stop(). + * @return null + */ + public function end() + { + $this->stop(); } /** diff --git a/tests/Template/TemplateTest.php b/tests/Template/TemplateTest.php index 803bc98a..8360982f 100644 --- a/tests/Template/TemplateTest.php +++ b/tests/Template/TemplateTest.php @@ -151,6 +151,21 @@ public function testSection() $this->assertEquals($this->template->render(), 'Hello World'); } + public function testReplaceSection() + { + vfsStream::create( + array( + 'template.php' => implode('\n', array( + 'layout("layout")?>start("test") ?>Hello Worldstop() ?>', + 'layout("layout")?>start("test") ?>See this instead!stop() ?>', + )), + 'layout.php' => 'section("test") ?>', + ) + ); + + $this->assertEquals($this->template->render(), 'See this instead!'); + } + public function testStartSectionWithInvalidName() { $this->setExpectedException('LogicException', 'The section name "content" is reserved.'); @@ -164,6 +179,19 @@ public function testStartSectionWithInvalidName() $this->template->render(); } + public function testNestSectionWithinAnotherSection() + { + $this->setExpectedException('LogicException', 'You cannot nest sections within other sections.'); + + vfsStream::create( + array( + 'template.php' => 'start("section1") ?>start("section2") ?>', + ) + ); + + $this->template->render(); + } + public function testStopSectionBeforeStarting() { $this->setExpectedException('LogicException', 'You must start a section before you can stop it.'); @@ -198,6 +226,42 @@ public function testNullSection() $this->assertEquals($this->template->render(), 'NULL'); } + public function testPushSection() + { + vfsStream::create( + array( + 'template.php' => implode('\n', array( + 'layout("layout")?>', + 'push("scripts") ?>end() ?>', + 'push("scripts") ?>end() ?>', + )), + 'layout.php' => 'section("scripts") ?>', + ) + ); + + $this->assertEquals($this->template->render(), ''); + } + + public function testPushWithMultipleSections() + { + vfsStream::create( + array( + 'template.php' => implode('\n', array( + 'layout("layout")?>', + 'push("scripts") ?>end() ?>', + 'start("test") ?>teststop() ?>', + 'push("scripts") ?>end() ?>', + )), + 'layout.php' => implode('\n', array( + 'section("test") ?>', + 'section("scripts") ?>', + )), + ) + ); + + $this->assertEquals($this->template->render(), 'test\n'); + } + public function testFetchFunction() { vfsStream::create(