Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added sections inheritance of fetched templates #306

Open
wants to merge 5 commits into
base: v3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest limit it to .idea

Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ doc/public
doc/data/versions.json
.generated
.phpunit.result.cache
.idea/.gitignore
.idea/modules.xml
.idea/php-test-framework.xml
.idea/php.xml
.idea/phpunit.xml
.idea/plates.iml
.idea/vcs.xml
composer.phar
54 changes: 33 additions & 21 deletions src/Template/Template.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace League\Plates\Template;

use Exception;
use League\Plates\Engine;
use League\Plates\Exception\TemplateNotFound;
use LogicException;
Expand Down Expand Up @@ -43,9 +42,10 @@ class Template

/**
* An array of section content.
* @var array
*
* @var TemplateSectionCollection
*/
protected $sections = array();
protected $sections;

/**
* The name of the section currently being rendered.
Expand Down Expand Up @@ -81,6 +81,7 @@ public function __construct(Engine $engine, $name)
{
$this->engine = $engine;
$this->name = new Name($engine, $name);
$this->sections = new TemplateSectionCollection();

$this->data($this->engine->getData($name));
}
Expand Down Expand Up @@ -173,7 +174,9 @@ public function render(array $data = array())

if (isset($this->layoutName)) {
$layout = $this->engine->make($this->layoutName);
$layout->sections = array_merge($this->sections, array('content' => $content));
$layout->sections->merge($this->sections);
$contentSectionName = 'content';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to use a attribute to declare it. In case someone want to change it.

$layout->sections[$contentSectionName] = $content;
$content = $layout->render($this->layoutData);
}

Expand Down Expand Up @@ -251,31 +254,31 @@ public function unshift($name)
*/
public function stop()
{
if (is_null($this->sectionName)) {
$sectionName = $this->sectionName;

if (is_null($sectionName)) {
throw new LogicException(
'You must start a section before you can stop it.'
);
}

if (!isset($this->sections[$this->sectionName])) {
$this->sections[$this->sectionName] = '';
if (!$this->sections->has($sectionName)) {
$this->sections[$sectionName] = '';
}

switch ($this->sectionMode) {
$sectionContent = ob_get_clean();

case self::SECTION_MODE_REWRITE:
$this->sections[$this->sectionName] = ob_get_clean();
break;

case self::SECTION_MODE_APPEND:
$this->sections[$this->sectionName] .= ob_get_clean();
break;
// if ob_clean failed for some reason let's just ignore the result
if ($sectionContent === false) {
return;
}

case self::SECTION_MODE_PREPEND:
$this->sections[$this->sectionName] = ob_get_clean().$this->sections[$this->sectionName];
break;
$this->sections->add(
$sectionName,
$sectionContent,
$this->sectionMode
);

}
$this->sectionName = null;
$this->sectionMode = self::SECTION_MODE_REWRITE;
$this->appendSection = false; /* for backward compatibility */
Expand Down Expand Up @@ -307,13 +310,22 @@ public function section($name, $default = null)

/**
* Fetch a rendered template.
*
* @param string $name
* @param array $data
* @return string
*/
public function fetch($name, array $data = array())
{
return $this->engine->render($name, $data);
$template = $this->engine->make($name);
$content = $template->render($data);

// some info like 'sections' are only filled during
// the render processing, so here we have a window to
// fetch them and join to this template.
$this->sections->merge($template->sections);

return $content;
}

/**
Expand All @@ -324,7 +336,7 @@ public function fetch($name, array $data = array())
*/
public function insert($name, array $data = array())
{
echo $this->engine->render($name, $data);
echo $this->fetch($name, $data);
}

/**
Expand Down
98 changes: 98 additions & 0 deletions src/Template/TemplateSection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

namespace League\Plates\Template;

/**
* Defines the object format of the data target
* to be rendered in a Template's Section.
*/
class TemplateSection
{
/**
* Section mode.
*
* @var int
*/
protected $mode;

/**
* Section content.
*
* @var string
*/
protected $content;

/**
* Section name.
*
* @var string
*/
protected $name;

/**
* @param string $name
* @param ?string $content
* @param ?int $mode
*/
public function __construct(string $name, $content = '', $mode = Template::SECTION_MODE_REWRITE)
{
$this->name = $name;
$this->content = $content;
$this->mode = $mode;
}

/**
* @param string $content
* @param int $mode
* @return void
*/
public function add(string $content, int $mode)
{
$this->mode = $mode;

// if this template doesn't have that section, so we just add it.
if (empty($this->content)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like !isset instead of empty. Some time ago I read that this would be faster.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's because empty also checks if the value represents an empty value like "".

$this->content = $content;
return;
}

// otherwise we need to consider the incoming section mode
if ($mode === Template::SECTION_MODE_REWRITE) {
$this->content = $content;
return;
}

if ($mode === Template::SECTION_MODE_APPEND) {
$this->content = $this->content . $content;
return;
}

if ($mode === Template::SECTION_MODE_PREPEND) {
$this->content = $content . $this->content;
}
}

/**
* @return string|null
*/
public function getContent(): string
{
return $this->content;
}

/**
* @return string
*/
public function getName(): string
{
return $this->name;
}

/**
* @return int
*/
public function getMode(): int
{
return $this->mode;
}
}
148 changes: 148 additions & 0 deletions src/Template/TemplateSectionCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php

namespace League\Plates\Template;

use ArrayAccess;
use InvalidArgumentException;

/**
* Collection of TemplateSections that can be used to fill Template's Sections.
* Here is defined a common API for merging Template Section data.
* NOTE: currently this is not iterable, so do not try this in a foreach.
*/
class TemplateSectionCollection implements ArrayAccess
{
/**
* @var array<string, TemplateSection>
*/
private $sections = array();

/**
* @param string $offset
*
* @return bool
*/
public function has(string $offset): bool
{
return array_key_exists($offset, $this->sections);
}

/**
* @param string $offset
*
* @return TemplateSection
*/
public function get(string $offset)
{
return $this->sections[$offset];
}

/**
* @param string $offset
* @param TemplateSection|null $value
*
* @return void
*/
public function set(string $offset, $value)
{
if (!is_string($offset)) {
throw new InvalidArgumentException('The desired section offset must be a string.');
}
if (!($value instanceof TemplateSection) && $value != null) {
throw new InvalidArgumentException('The section set must be of type TemplateSection.');
}
$this->sections[$offset] = $value;
}

/**
* @param string $offset
*
* @return bool
*/
public function offsetExists($offset): bool
{
if (!is_string($offset)) {
throw new InvalidArgumentException('The desired section offset must be a string.');
}
return $this->has($offset);
}

/**
* @param string $offset
*
* @return string
*/
public function offsetGet($offset)
{
if (!is_string($offset)) {
throw new InvalidArgumentException('The desired section offset must be a string.');
}
return $this->get($offset)->getContent();
}

/**
* @param string $offset
* @param string $value
*
* @return void
*/
public function offsetSet($offset, $value): void
{
if (!is_string($offset)) {
throw new InvalidArgumentException('The desired section offset must be a string.');
}
$this->add($offset, $value, Template::SECTION_MODE_REWRITE);
}

/**
* @param string $offset
*
* @return void
*/
public function offsetUnset($offset)
{
if (!is_string($offset)) {
throw new InvalidArgumentException('The desired section offset must be a string.');
}
$this->sections[$offset] = null;
unset($this->sections[$offset]);
}

/**
* Pushes the given section content to the sections array.
* You can use the $mode to merge the content to an existing
* content if that section content already exists.
*
* @param string $name
* @param string $content
* @param ?int $mode
*
* @return void
*/
public function add(string $name, string $content, $mode = Template::SECTION_MODE_APPEND)
{
if ($this->has($name)) {
$this->sections[$name]->add($content, $mode);
return;
}
$this->sections[$name] = new TemplateSection($name, $content, $mode);
}

/**
* Merges another Template Sections collection into
* this one taking in consideration the template
* section's modes.
*
* @return void
*/
public function merge(TemplateSectionCollection $templateSections)
{
foreach ($templateSections->sections as $section) {
$this->add(
$section->getName(),
$section->getContent(),
$section->getMode()
);
}
}
}
Loading