Skip to content

Commit

Permalink
Add the ability to append content to sections.
Browse files Browse the repository at this point in the history
Closes #135.
  • Loading branch information
reinink committed Dec 27, 2016
1 parent 5874ba8 commit 576b6ce
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 8 deletions.
16 changes: 14 additions & 2 deletions docs/templates/sections.md
Expand Up @@ -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
<?php $this->start('welcome') ?>
Expand All @@ -22,6 +22,18 @@ You define the name of the section in the `start()` function, and end the sectio
<?php $this->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
<?php $this->push('scripts') ?>
<script src="example.js"></script>
<?php $this->end() ?>
~~~

<p class="message-notice">The <code>end()</code> function is simply an alias of <code>stop()</code>. These functions can be used interchangeably.</p>

## 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.
Expand Down
2 changes: 2 additions & 0 deletions example/templates/layout.php
Expand Up @@ -6,5 +6,7 @@

<?=$this->section('content')?>

<?=$this->section('scripts')?>

</body>
</html>
8 changes: 7 additions & 1 deletion example/templates/profile.php
Expand Up @@ -3,4 +3,10 @@
<h1>User Profile</h1>
<p>Hello, <?=$this->e($name)?>!</p>

<?php $this->insert('sidebar') ?>
<?php $this->insert('sidebar') ?>

<?php $this->push('scripts') ?>
<script>
// Some JavaScript
</script>
<?php $this->end() ?>
51 changes: 46 additions & 5 deletions src/Template/Template.php
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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();
}

/**
Expand Down
64 changes: 64 additions & 0 deletions tests/Template/TemplateTest.php
Expand Up @@ -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(
'<?php $this->layout("layout")?><?php $this->start("test") ?>Hello World<?php $this->stop() ?>',
'<?php $this->layout("layout")?><?php $this->start("test") ?>See this instead!<?php $this->stop() ?>',
)),
'layout.php' => '<?php echo $this->section("test") ?>',
)
);

$this->assertEquals($this->template->render(), 'See this instead!');
}

public function testStartSectionWithInvalidName()
{
$this->setExpectedException('LogicException', 'The section name "content" is reserved.');
Expand All @@ -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' => '<?php $this->start("section1") ?><?php $this->start("section2") ?>',
)
);

$this->template->render();
}

public function testStopSectionBeforeStarting()
{
$this->setExpectedException('LogicException', 'You must start a section before you can stop it.');
Expand Down Expand Up @@ -198,6 +226,42 @@ public function testNullSection()
$this->assertEquals($this->template->render(), 'NULL');
}

public function testPushSection()
{
vfsStream::create(
array(
'template.php' => implode('\n', array(
'<?php $this->layout("layout")?>',
'<?php $this->push("scripts") ?><script src="example1.js"></script><?php $this->end() ?>',
'<?php $this->push("scripts") ?><script src="example2.js"></script><?php $this->end() ?>',
)),
'layout.php' => '<?php echo $this->section("scripts") ?>',
)
);

$this->assertEquals($this->template->render(), '<script src="example1.js"></script><script src="example2.js"></script>');
}

public function testPushWithMultipleSections()
{
vfsStream::create(
array(
'template.php' => implode('\n', array(
'<?php $this->layout("layout")?>',
'<?php $this->push("scripts") ?><script src="example1.js"></script><?php $this->end() ?>',
'<?php $this->start("test") ?>test<?php $this->stop() ?>',
'<?php $this->push("scripts") ?><script src="example2.js"></script><?php $this->end() ?>',
)),
'layout.php' => implode('\n', array(
'<?php echo $this->section("test") ?>',
'<?php echo $this->section("scripts") ?>',
)),
)
);

$this->assertEquals($this->template->render(), 'test\n<script src="example1.js"></script><script src="example2.js"></script>');
}

public function testFetchFunction()
{
vfsStream::create(
Expand Down

0 comments on commit 576b6ce

Please sign in to comment.