-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Add proposal for template renderer #1280
base: master
Are you sure you want to change the base?
Changes from 6 commits
e568a17
ca5ff57
fbbd629
f0e55b3
09a9637
f62eafa
970939f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
Common Interface for Rendering Templates | ||
======================================== | ||
|
||
This document describes a common interface for template renderers. | ||
|
||
The goal set by `TemplateRendererInterface` is to standardize how frameworks, libraries and CMSs | ||
render their templates so that projects are more free to use the template renderer they prefer. | ||
|
||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", | ||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be | ||
interpreted as described in [RFC 2119][]. | ||
|
||
The word `implementor` in this document is to be interpreted as someone | ||
implementing the `TemplateRendererInterface` in a [template engine][] library. | ||
Users of template renderer are referred to as `user`. | ||
The word `enduser` in this document is to be interpreted as someone using | ||
a library, framework, CMS created by a `user`. | ||
|
||
[RFC 2119]: http://tools.ietf.org/html/rfc2119 | ||
|
||
## Goal | ||
|
||
Having common interfaces for rendering templates allows developers to create libraries that can interact with many frameworks and other libraries in a common fashion. | ||
|
||
Some examples may use the Interface: | ||
|
||
- Content Management Systems (Sulu CMS, Drupal, Typo3, Contao CMS, ...) | ||
- E-Commerce Platforms (Sylius, Spryker) | ||
- Newsletter/Mail Libraries (Symfony Mailer, Abstractions over Mailchimp and other Newsletter tools) | ||
- Anything following ["Separating content from presentation"](https://en.wikipedia.org/wiki/Separation_of_content_and_presentation) where the presentation is project specific. | ||
|
||
Some examples may implement the Interface or providing a bridge: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yii has alike interface https://github.com/yiisoft/view/blob/master/src/TemplateRendererInterface.php with the difference that we're passing a rendering context as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thx for mentioning yii views. Looking at the example it works the same way That yii uses then in the I will add it also the the list. Please check my details in the PR description about it if I did write nothing wrong about it. |
||
|
||
- Blade (Laravel Framework) | ||
- Laminas View | ||
- Latte (Nette Framework) | ||
- Smarty | ||
- Sulu CMS | ||
- Twig (Symfony Framework) | ||
- Typo3 | ||
|
||
## Definitions | ||
|
||
* **Template** - A string representation of a template. | ||
* **Context** - An array of context data given to the rendered template. | ||
* **TemplateRenderer** - A renderer which will render the template with the given context and return the rendered content as string. | ||
|
||
### Template | ||
|
||
A template MUST be a string representation of a given template supported by the template renderer. It MAY be a file path | ||
to the template file, but it can also be a virtual name or path supported only by a specific template renderer. The | ||
template is not limited by specific characters by definition but a template renderer MAY support only specific one. | ||
|
||
### Context | ||
|
||
A context MUST be an array of the available variables given to the template renderer. The array keys represent the | ||
variable names and MUST be strings. The array values represent the variable values and can be anything and | ||
. | ||
|
||
### TemplateRenderer | ||
|
||
A template renderer is a service implementing the `TemplateRendererInterface`. It MUST be responsible of rendering a | ||
supported template given an OPTIONAL context. It MUST return the rendered content of the template as a string. | ||
If the template was not found by the template renderer, an Exception implementing the `TemplateNotFoundExceptionInterface` | ||
MUST be thrown. The template renderer SHALL NOT output/print/stream directly. | ||
|
||
## Usage | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section definitely belongs to metadata document. |
||
|
||
While the implementor of `TemplateRendererInterface` MUST make sure that the template renderer behave like defined | ||
above. The user of `TemplateRendererInterface` MUST allow when providing a library, application, cms for an enduser | ||
using the Interface to give or configure the `template` used by the template renderer. This can be achieved with any | ||
type of injection or configuration. | ||
|
||
Basic implementor implementation: | ||
|
||
```php | ||
<?php | ||
|
||
use Psr\TemplateRenderer\TemplateRendererInterface; | ||
|
||
class TemplateRenderer implements TemplateRendererInterface | ||
{ | ||
public function render(string $template, array $context = []): string | ||
{ | ||
switch ($template) { | ||
case 'home.tpl'; | ||
|
||
return $this->renderTemplate('<p>{{name}}</p>', $context); | ||
default: | ||
throw new TemplateNotFoundException($template); | ||
} | ||
} | ||
|
||
/** | ||
* @param array<string, mixed> $context | ||
* @return string | ||
*/ | ||
private function renderTemplate(string $content, array $context): string | ||
{ | ||
foreach ($context as $key => $value) { | ||
$content = str_replace('{{' . $key . '}}', $context[$key], $content); | ||
} | ||
|
||
return $content; | ||
} | ||
} | ||
|
||
use Psr\TemplateRenderer\TemplateNotFoundExceptionInterface; | ||
|
||
class TemplateNotFoundException extends \RuntimeException implements TemplateNotFoundExceptionInterface | ||
{ | ||
public function __construct(private string $template, ?\Throwable $previous = null) | ||
{ | ||
parent::__construct('Template not found: "' . $template . '"', 0 , $previous); | ||
} | ||
|
||
public function getTemplate(): string | ||
{ | ||
return $this->template; | ||
} | ||
} | ||
``` | ||
|
||
Basic user implementation: | ||
|
||
```php | ||
<?php | ||
|
||
use Psr\TemplateRenderer\TemplateRendererInterface; | ||
|
||
class SomeController | ||
{ | ||
public function __construct( | ||
private TemplateRendererInterface $templateRenderer, | ||
private string $template, | ||
) | ||
|
||
public function someAction(): string | ||
{ | ||
$context = [/* load something */]; | ||
|
||
return $this->templateRenderer->render($this->template, $context); | ||
} | ||
} | ||
``` | ||
|
||
Example enduser implementation A: | ||
|
||
```php | ||
<?php | ||
|
||
$controller = new Controller($twig, '@Context/pages/mail.html.twig'); | ||
$controller->someAction(); | ||
``` | ||
|
||
Example enduser implementation B: | ||
|
||
```php | ||
<?php | ||
|
||
$controller = new Controller($blade, 'mail'); | ||
$controller->someAction(); | ||
``` | ||
|
||
Example enduser implementation C: | ||
|
||
```php | ||
<?php | ||
|
||
$controller = new Controller($latte, 'mail.latte'); | ||
$controller->someAction(); | ||
``` | ||
|
||
## Interfaces | ||
|
||
### TemplateRendererInterface | ||
|
||
```php | ||
<?php | ||
|
||
namespace Psr\TemplateRenderer; | ||
|
||
interface TemplateRendererInterface { | ||
/** | ||
* Render the template with the given context data. | ||
* | ||
* @param string $template | ||
* @param array<string, mixed> $context | ||
* | ||
* @return string | ||
*/ | ||
public function render(string $template, array $context = []): string; | ||
} | ||
``` | ||
|
||
### TemplateNotFoundExceptionInterface | ||
|
||
```php | ||
<?php | ||
|
||
namespace Psr\TemplateRenderer; | ||
|
||
interface TemplateNotFoundExceptionInterface | ||
alexander-schranz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
public function getTemplate(): string; | ||
} | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think details should be moved to a meta-document.