Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Commit

Permalink
Merge branch 'feature/143' into develop
Browse files Browse the repository at this point in the history
Close #143
Close #151
  • Loading branch information
weierophinney committed Oct 10, 2015
2 parents d0ce891 + e9a7d2c commit 9595d7d
Show file tree
Hide file tree
Showing 14 changed files with 441 additions and 2 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ All notable changes to this project will be documented in this file, in reverse
`Zend\Expressive\Template\Twig`.
- `Zend\Expressive\Template\ZendViewRenderer`, replacing
`Zend\Expressive\Template\ZendView`.
- [#143](https://github.com/zendframework/zend-expressive/pull/143) adds
the method `addDefaultParam($templateName, $param, $value)` to
`TemplateRendererInterface`, allowing users to specify global and
template-specific default parameters to use when rendering. To implement the
feature, the patch also provides `Zend\Expressive\Template\DefaultParamsTrait`
to simplify incorporating the feature in implementations.

### Deprecated

Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"container-interop/container-interop": "^1.1",
"psr/http-message": "^1.0",
"zendframework/zend-diactoros": "^1.1",
"zendframework/zend-stdlib": "^2.7",
"zendframework/zend-stratigility": "^1.1"
},
"require-dev": {
Expand Down
74 changes: 74 additions & 0 deletions doc/book/template/interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,27 @@ interface TemplateRendererInterface
* @return TemplatePath[]
*/
public function getPaths();

/**
* Add a default parameter to use with a template.
*
* Use this method to provide a default parameter to use when a template is
* rendered. The parameter may be overridden by providing it when calling
* `render()`, or by calling this method again with a null value.
*
* The parameter will be specific to the template name provided. To make
* the parameter available to any template, pass the TEMPLATE_ALL constant
* for the template name.
*
* If the default parameter existed previously, subsequent invocations with
* the same template name and parameter name will overwrite.
*
* @param string $templateName Name of template to which the param applies;
* use TEMPLATE_ALL to apply to all templates.
* @param string $param Param name.
* @param mixed $value
*/
public function addDefaultParam($templateName, $param, $value);
}
```

Expand Down Expand Up @@ -119,3 +140,56 @@ $content = $renderer->render('message', [

It is up to the underlying template engine to determine how to perform the
injections.

### Default params

The `TemplateRendererInterface` defines the method `addDefaultParam()`. This
method can be used to specify default parameters to use when rendering a
template. The signature is:

```php
public function addDefaultParam($templateName, $param, $value)
```

If you want a parameter to be used for *every* template, you can specify the
constant `TemplateRendererInterface::TEMPLATE_ALL` for the `$templateName`
parameter.

When rendering, parameters are considered in the following order, with later
items having precedence over earlier ones:

- Default parameters specified for all templates.
- Default parameters specified for the template specified at rendering.
- Parameters specified when rendering.

As an example, if we did the following:

```php
$renderer->addDefaultParam($renderer::TEMPLATE_ALL, 'foo', 'bar');
$renderer->addDefaultParam($renderer::TEMPLATE_ALL, 'bar', 'baz');
$renderer->addDefaultParam($renderer::TEMPLATE_ALL, 'baz', 'bat');

$renderer->addDefaultParam('example', 'foo', 'template default foo');
$renderer->addDefaultParam('example', 'bar', 'template default bar');

$content = $renderer->render('example', [
'foo' => 'override',
]);
```

Then we can expect the following substitutions will occur when rendering:

- References to the "foo" variable will contain "override".
- References to the "bar" variable will contain "template default bar".
- References to the "baz" variable will contain "bat".

> #### Support for default params
>
> The support for default params will often be renderer-specific. The reason is
> because the `render()` signature does not specify a type for `$params`, in
> order to allow passing alternative arguments such as view models. In such
> cases, the implementation will indicate its behavior when default parameters
> are specified, but a given `$params` argument does not support it.
>
> At the time of writing, each of the Plates, Twig, and zend-view
> implementations support the feature.
86 changes: 86 additions & 0 deletions src/Template/DefaultParamsTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @see https://github.com/zendframework/zend-expressive for the canonical source repository
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license https://github.com/zendframework/zend-expressive/blob/master/LICENSE.md New BSD License
*/

namespace Zend\Expressive\Template;

use Traversable;
use Zend\Expressive\Exception;
use Zend\Stdlib\ArrayUtils;

trait DefaultParamsTrait
{
/**
* @var array
*/
private $defaultParams = [];

/**
* Add a default parameter to use with a template.
*
* Use this method to provide a default parameter to use when a template is
* rendered. The parameter may be overridden by providing it when calling
* `render()`, or by calling this method again with a null value.
*
* The parameter will be specific to the template name provided. To make
* the parameter available to any template, pass the TEMPLATE_ALL constant
* for the template name.
*
* If the default parameter existed previously, subsequent invocations with
* the same template name and parameter name will overwrite.
*
* @param string $templateName Name of template to which the param applies;
* use TEMPLATE_ALL to apply to all templates.
* @param string $param Param name.
* @param mixed $value
*/
public function addDefaultParam($templateName, $param, $value)
{
if (! is_string($templateName) || empty($templateName)) {
throw new Exception\InvalidArgumentException(sprintf(
'$templateName must be a non-empty string; received %s',
(is_object($templateName) ? get_class($templateName) : gettype($templateName))
));
}

if (! is_string($param) || empty($param)) {
throw new Exception\InvalidArgumentException(sprintf(
'$param must be a non-empty string; received %s',
(is_object($param) ? get_class($param) : gettype($param))
));
}

if (! isset($this->defaultParams[$templateName])) {
$this->defaultParams[$templateName] = [];
}

$this->defaultParams[$templateName][$param] = $value;
}

/**
* Returns merged global, template-specific and given params
*
* @param string $template
* @param array $params
* @return array
*/
private function mergeParams($template, array $params)
{
$globalDefaults = isset($this->defaultParams[TemplateRendererInterface::TEMPLATE_ALL])
? $this->defaultParams[TemplateRendererInterface::TEMPLATE_ALL]
: [];

$templateDefaults = isset($this->defaultParams[$template])
? $this->defaultParams[$template]
: [];

$defaults = ArrayUtils::merge($globalDefaults, $templateDefaults);

return ArrayUtils::merge($defaults, $params);
}
}
34 changes: 34 additions & 0 deletions src/Template/PlatesRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use League\Plates\Engine;
use ReflectionProperty;
use Zend\Expressive\Exception;

/**
* Template implementation bridging league/plates
Expand Down Expand Up @@ -88,6 +89,39 @@ public function getPaths()
return $paths;
}

/**
* {@inheritDoc}
*
* Proxies to the Plate Engine's `addData()` method.
*
* {@inheritDoc}
*/
public function addDefaultParam($templateName, $param, $value)
{
if (! is_string($templateName) || empty($templateName)) {
throw new Exception\InvalidArgumentException(sprintf(
'$templateName must be a non-empty string; received %s',
(is_object($templateName) ? get_class($templateName) : gettype($templateName))
));
}

if (! is_string($param) || empty($param)) {
throw new Exception\InvalidArgumentException(sprintf(
'$param must be a non-empty string; received %s',
(is_object($param) ? get_class($param) : gettype($param))
));
}

$params = [$param => $value];

if ($templateName === self::TEMPLATE_ALL) {
$templateName = null;
}

$this->template->addData($params, $templateName);
}


/**
* Create a default Plates engine
*
Expand Down
26 changes: 26 additions & 0 deletions src/Template/TemplateRendererInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
*/
interface TemplateRendererInterface
{
/**
* @const string Value indicating all templates; used with `addDefaultParam()`.
*/
const TEMPLATE_ALL = '*';

/**
* Render a template, optionally with parameters.
*
Expand Down Expand Up @@ -43,4 +48,25 @@ public function addPath($path, $namespace = null);
* @return TemplatePath[]
*/
public function getPaths();

/**
* Add a default parameter to use with a template.
*
* Use this method to provide a default parameter to use when a template is
* rendered. The parameter may be overridden by providing it when calling
* `render()`, or by calling this method again with a null value.
*
* The parameter will be specific to the template name provided. To make
* the parameter available to any template, pass the TEMPLATE_ALL constant
* for the template name.
*
* If the default parameter existed previously, subsequent invocations with
* the same template name and parameter name will overwrite.
*
* @param string $templateName Name of template to which the param applies;
* use TEMPLATE_ALL to apply to all templates.
* @param string $param Param name.
* @param mixed $value
*/
public function addDefaultParam($templateName, $param, $value);
}
9 changes: 8 additions & 1 deletion src/Template/TwigRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
class TwigRenderer implements TemplateRendererInterface
{
use ArrayParametersTrait;
use DefaultParamsTrait;

/**
* @var string
Expand Down Expand Up @@ -89,8 +90,14 @@ private function getDefaultLoader()
*/
public function render($name, $params = [])
{
// Merge parameters based on requested template name
$params = $this->mergeParams($name, $this->normalizeParams($params));

$name = $this->normalizeTemplate($name);
$params = $this->normalizeParams($params);

// Merge parameters based on normalized template name
$params = $this->mergeParams($name, $params);

return $this->template->render($name, $params);
}

Expand Down
4 changes: 3 additions & 1 deletion src/Template/ZendViewRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
class ZendViewRenderer implements TemplateRendererInterface
{
use ArrayParametersTrait;
use DefaultParamsTrait;

/**
* @var ViewModel
Expand Down Expand Up @@ -118,8 +119,9 @@ public function __construct(RendererInterface $renderer = null, $layout = null)
*/
public function render($name, $params = [])
{
$params = $this->mergeParams($name, $this->normalizeParams($params));
return $this->renderModel(
$this->createModel($name, $this->normalizeParams($params)),
$this->createModel($name, $params),
$this->renderer
);
}
Expand Down
70 changes: 70 additions & 0 deletions test/Template/PlatesRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,74 @@ public function testProperlyResolvesNamespacedTemplate()

$this->assertSame($expected, $test);
}

public function testAddParameterToOneTemplate()
{
$renderer = new PlatesRenderer();
$renderer->addPath(__DIR__ . '/TestAsset');
$name = 'Plates';
$renderer->addDefaultParam('plates', 'name', $name);
$result = $renderer->render('plates');
$content = file_get_contents(__DIR__ . '/TestAsset/plates.php');
$content= str_replace('<?=$this->e($name)?>', $name, $content);
$this->assertEquals($content, $result);

// @fixme hack to work around https://github.com/thephpleague/plates/issues/60, remove if ever merged
set_error_handler(function ($error, $message) {
$this->assertContains('Undefined variable: name', $message);
return true;
}, E_NOTICE);
$renderer->render('plates-2');
restore_error_handler();

$content= str_replace('<?=$this->e($name)?>', '', $content);
$this->assertEquals($content, $result);
}

public function testAddSharedParameters()
{
$renderer = new PlatesRenderer();
$renderer->addPath(__DIR__ . '/TestAsset');
$name = 'Plates';
$renderer->addDefaultParam($renderer::TEMPLATE_ALL, 'name', $name);
$result = $renderer->render('plates');
$content = file_get_contents(__DIR__ . '/TestAsset/plates.php');
$content= str_replace('<?=$this->e($name)?>', $name, $content);
$this->assertEquals($content, $result);
$result = $renderer->render('plates-2');
$content = file_get_contents(__DIR__ . '/TestAsset/plates-2.php');
$content= str_replace('<?=$this->e($name)?>', $name, $content);
$this->assertEquals($content, $result);
}

public function testOverrideSharedParametersPerTemplate()
{
$renderer = new PlatesRenderer();
$renderer->addPath(__DIR__ . '/TestAsset');
$name = 'Plates';
$name2 = 'Saucers';
$renderer->addDefaultParam($renderer::TEMPLATE_ALL, 'name', $name);
$renderer->addDefaultParam('plates-2', 'name', $name2);
$result = $renderer->render('plates');
$content = file_get_contents(__DIR__ . '/TestAsset/plates.php');
$content= str_replace('<?=$this->e($name)?>', $name, $content);
$this->assertEquals($content, $result);
$result = $renderer->render('plates-2');
$content = file_get_contents(__DIR__ . '/TestAsset/plates-2.php');
$content= str_replace('<?=$this->e($name)?>', $name2, $content);
$this->assertEquals($content, $result);
}

public function testOverrideSharedParametersAtRender()
{
$renderer = new PlatesRenderer();
$renderer->addPath(__DIR__ . '/TestAsset');
$name = 'Plates';
$name2 = 'Saucers';
$renderer->addDefaultParam($renderer::TEMPLATE_ALL, 'name', $name);
$result = $renderer->render('plates', ['name' => $name2]);
$content = file_get_contents(__DIR__ . '/TestAsset/plates.php');
$content= str_replace('<?=$this->e($name)?>', $name2, $content);
$this->assertEquals($content, $result);
}
}
Loading

0 comments on commit 9595d7d

Please sign in to comment.