Skip to content

Commit

Permalink
Add support for Twig as template engine
Browse files Browse the repository at this point in the history
  • Loading branch information
lcobucci committed Apr 22, 2018
1 parent 7e10c7a commit 46b3702
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ We provide some basic formatters by default:
* `StringCast`
* `JmsSerializer` (requires you to also install and configure [`jms/serializer`](https://jmsyst.com/libs/serializer))
* `Plates` (requires you to also install and configure [`league/plates`](http://platesphp.com))
* `Twig` (requires you to also install and configure [`twig/twig`](https://twig.symfony.com))

If you want to create a customised formatter the only thing needed is to
implement the `Formatter` interface:
Expand Down
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@
"phpstan/phpstan-strict-rules": "^0.10@dev",
"phpunit/phpunit": "^7.0",
"squizlabs/php_codesniffer": "^3.2",
"twig/twig": "^2.0",
"zendframework/zend-diactoros": "^1.7"
},
"suggest": {
"jms/serializer": "For content formatting using a more flexible serializer",
"league/plates": "For content formatting using Plates as template engine",
"middlewares/negotiation": "For acceptable format identification",
"twig/twig": "For content formatting using Twig as template engine",
"zendframework/zend-diactoros": "For concrete implementation of PSR-7"
},
"autoload": {
Expand Down
61 changes: 61 additions & 0 deletions src/Formatter/Twig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);

namespace Lcobucci\ContentNegotiation\Formatter;

use Lcobucci\ContentNegotiation\ContentCouldNotBeFormatted;
use Lcobucci\ContentNegotiation\Formatter;
use Throwable;
use Twig_Environment;

final class Twig implements Formatter
{
private const DEFAULT_ATTRIBUTE = 'template';

/**
* @var Twig_Environment
*/
private $environment;

/**
* @var string
*/
private $attributeName;

public function __construct(
Twig_Environment $environment,
string $attributeName = self::DEFAULT_ATTRIBUTE
) {
$this->environment = $environment;
$this->attributeName = $attributeName;
}

/**
* {@inheritdoc}
*/
public function format($content, array $attributes = []): string
{
try {
return $this->render($content, $attributes);
} catch (Throwable $exception) {
throw new ContentCouldNotBeFormatted(
'An error occurred while formatting using twig',
$exception->getCode(),
$exception
);
}
}

/**
* @param mixed $content
* @param mixed[] $attributes
*
* @throws Throwable
*/
private function render($content, array $attributes = []): string
{
$template = $attributes[$this->attributeName] ?? '';

return $this->environment->render($template, ['content' => $content]);
}
}
8 changes: 8 additions & 0 deletions templates/twig/person.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<section>
<dl>
<dt>Identifier</dt>
<dd>{{ content.id }}</dd>
<dt>Name</dt>
<dd>{{ content.name }}</dd>
</dl>
</section>
82 changes: 82 additions & 0 deletions tests/Formatter/TwigTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);

namespace Lcobucci\ContentNegotiation\Tests\Formatter;

use Lcobucci\ContentNegotiation\ContentCouldNotBeFormatted;
use Lcobucci\ContentNegotiation\Formatter\Twig;
use Lcobucci\ContentNegotiation\Tests\PersonDto;
use PHPUnit\Framework\TestCase;
use Twig_Environment;
use Twig_Loader_Filesystem;
use function dirname;

/**
* @coversDefaultClass \Lcobucci\ContentNegotiation\Formatter\Twig
*/
final class TwigTest extends TestCase
{
/**
* @var Twig_Environment
*/
private $environment;

/**
* @before
*/
public function configureEngine(): void
{
$this->environment = new Twig_Environment(
new Twig_Loader_Filesystem('templates/twig', dirname(__DIR__, 2) . '/')
);
}

/**
* @test
*
* @covers ::__construct()
* @covers ::format()
* @covers ::render()
*/
public function formatShouldReturnContentFormattedByPlates(): void
{
$formatter = new Twig($this->environment);
$content = $formatter->format(new PersonDto(1, 'Testing'), ['template' => 'person.twig']);

self::assertContains('<dd>1</dd>', $content);
self::assertContains('<dd>Testing</dd>', $content);
}

/**
* @test
*
* @covers ::__construct()
* @covers ::format()
* @covers ::render()
*/
public function formatShouldReadTemplateNameFromCustomAttribute(): void
{
$formatter = new Twig($this->environment, 'fancy!');
$content = $formatter->format(new PersonDto(1, 'Testing'), ['fancy!' => 'person.twig']);

self::assertContains('<dd>1</dd>', $content);
self::assertContains('<dd>Testing</dd>', $content);
}

/**
* @test
*
* @covers ::__construct()
* @covers ::format()
* @covers ::render()
*/
public function formatShouldConvertAnyTwigException(): void
{
$formatter = new Twig($this->environment);

$this->expectException(ContentCouldNotBeFormatted::class);
$this->expectExceptionMessage('An error occurred while formatting using twig');

$formatter->format(new PersonDto(1, 'Testing'), ['template' => 'no-template-at-all']);
}
}

0 comments on commit 46b3702

Please sign in to comment.