From 8de909bcbce162d8bbecedd3283e1003d762322c Mon Sep 17 00:00:00 2001 From: Anton Ukhanev Date: Fri, 28 Feb 2020 15:16:58 +0100 Subject: [PATCH 1/7] Added template factory --- .../PhpTemplate/FilePathTemplateFactory.php | 49 ++++++++ test/functional/Template/PhpTemplateTest.php | 113 ++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 src/Template/PhpTemplate/FilePathTemplateFactory.php diff --git a/src/Template/PhpTemplate/FilePathTemplateFactory.php b/src/Template/PhpTemplate/FilePathTemplateFactory.php new file mode 100644 index 0000000..3b27472 --- /dev/null +++ b/src/Template/PhpTemplate/FilePathTemplateFactory.php @@ -0,0 +1,49 @@ +evaluatorFactory = $evaluatorFactory; + $this->defaultContext = $defaultContext; + $this->functions = $functions; + } + + /** + * @inheritDoc + */ + public function fromPath(string $templatePath): TemplateInterface + { + $evaluator = $this->evaluatorFactory->fromFilePath($templatePath); + $template = new PhpTemplate($evaluator, $this->defaultContext, $this->functions); + + return $template; + } +} \ No newline at end of file diff --git a/test/functional/Template/PhpTemplateTest.php b/test/functional/Template/PhpTemplateTest.php index 16c3ba0..81aa42e 100644 --- a/test/functional/Template/PhpTemplateTest.php +++ b/test/functional/Template/PhpTemplateTest.php @@ -4,8 +4,13 @@ use ArrayAccess; use ArrayObject; +use Dhii\Output\PhpEvaluator\FilePhpEvaluatorFactory; +use Dhii\Output\PhpEvaluator\FilePhpEvaluatorFactoryInterface; use Dhii\Output\PhpEvaluator\PhpEvaluatorInterface; +use Dhii\Output\Template\PhpTemplate\FilePathTemplateFactory; use Exception; +use org\bovigo\vfs\vfsStream; +use org\bovigo\vfs\vfsStreamDirectory; use PHPUnit\Framework\TestCase; use Dhii\Output\Template\PhpTemplate as TestSubject; use PHPUnit_Framework_MockObject_MockObject as MockObject; @@ -16,6 +21,15 @@ */ class PhpTemplateTest extends TestCase { + /** @var vfsStreamDirectory */ + protected $fs; + + public function setUp() + { + parent::setUp(); + $this->fs = vfsStream::setup(); + } + /** * Creates a new instance of the test subject. * @@ -96,6 +110,42 @@ public function createContainer(array $data): ContainerInterface return $mock; } + /** + * Creates a new evaluator factory mock instance. + * + * @return FilePhpEvaluatorFactory&MockObject The new instance. + */ + public function createEvaluatorFactory(): FilePhpEvaluatorFactory + { + $mock = $this->getMockBuilder(FilePhpEvaluatorFactory::class) + ->setMethods(null) + ->getMock(); + + return $mock; + } + + /** + * Creates a new template factory mock instance. + * + * @param FilePhpEvaluatorFactoryInterface $evaluatorFactory + * @param array $defaultContext + * @param array $functions + * + * @return FilePathTemplateFactory&MockObject The new factory mock. + */ + public function createFactory( + FilePhpEvaluatorFactoryInterface $evaluatorFactory, + array $defaultContext, + array $functions + ): FilePathTemplateFactory { + $mock = $this->getMockBuilder(FilePathTemplateFactory::class) + ->setMethods(null) + ->setConstructorArgs([$evaluatorFactory, $defaultContext, $functions]) + ->getMock(); + + return $mock; + } + /** * Provides data useful for testing rendering with different contexts. * @@ -116,6 +166,69 @@ public function renderDataProvider(): array ]; } + /** + * Creates a virtual file with content, and retrieves its path. + * + * @param string $content The content for the file. + * + * @return string The path to the file. + */ + public function getFilePath(string $content): string + { + $fileName = uniqid() . '.php'; + $filePath = $this->fs->url() . "/$fileName"; + + file_put_contents($filePath, $content); + + return $filePath; + } + + /** + * Tests that a factory creates a template that produces correct output. + * + * This is an end-to-end test which tests all of the functionality related to a PHP template together: + * + * - It uses a real evaluator factory and real evaluators, which evaluate a real PHP template file + * in a real, albeit virtualized, filesystem. + * - It uses a real PHP template implementation. + * - It uses a real template, which has + * * Explicit PHP output (by using `echo `). + * * Implicit PHP output (by just having content outside of PHP). + * * Retrieves a value from context explicitly provided at render time. + * * Retrieves a value from default context provided via the factory. + * * Passes value through a custom function provided via the factory. + * + * Pretty much, this tests the whole happy path from start to finish. + */ + public function testFactoryE2e() + { + { + $evalFactory = $this->createEvaluatorFactory(); + $defaultKey = uniqid('default-key'); + $defaultValue = uniqid('default-value'); + $contextKey = uniqid('context-key'); + $contextValue = uniqid('context-value'); + $defaultContext = [$defaultKey => $defaultValue]; + $funcName = uniqid('func-name'); + $func = function ($value) { return substr($value, 0, 15); }; + $functions = [$funcName => $func]; + $context = [$contextKey => $contextValue]; + $contentSeparator = uniqid('separator'); + $content = "$contentSeparator"; + $funcResult = $func($contextValue); + $expectedOutput = "{$defaultValue}{$contentSeparator}{$funcResult}"; + $subject = $this->createFactory($evalFactory, $defaultContext, $functions); + $path = $this->getFilePath($content); + } + + { + $result = $subject->fromPath($path); + $output = $result->render($context); + + $this->assertEquals($expectedOutput, $output); + } + } + /** * Tests that rendering works correctly. * From 3a24b4650850aacd7617680af8ed764ca8241933 Mon Sep 17 00:00:00 2001 From: Anton Ukhanev Date: Fri, 28 Feb 2020 15:23:31 +0100 Subject: [PATCH 2/7] Corrected readme badges - Changed build badge branch to `develop`. - Removed Dhii standards badge. --- README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 341816a..5a7eafb 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ -# Dhii - Php Template - -[![Build Status](https://travis-ci.org/dhii/php-template.svg?branch=master)](https://travis-ci.org/dhii/php-template) -[![Code Climate](https://codeclimate.com/github/Dhii/php-template/badges/gpa.svg)](https://codeclimate.com/github/Dhii/php-template) -[![Test Coverage](https://codeclimate.com/github/Dhii/php-template/badges/coverage.svg)](https://codeclimate.com/github/Dhii/php-template/coverage) -[![Latest Stable Version](https://poser.pugx.org/dhii/php-template/version)](https://packagist.org/packages/dhii/php-template) -[![This package complies with Dhii standards](https://img.shields.io/badge/Dhii-Compliant-green.svg?style=flat-square)][Dhii] - -A concrete PHP (PHTML) template implementation. - -[Dhii]: https://github.com/Dhii/dhii +# Dhii - Php Template + +[![Build Status](https://travis-ci.org/dhii/php-template.svg?branch=develop)](https://travis-ci.org/dhii/php-template) +[![Code Climate](https://codeclimate.com/github/Dhii/php-template/badges/gpa.svg)](https://codeclimate.com/github/Dhii/php-template) +[![Test Coverage](https://codeclimate.com/github/Dhii/php-template/badges/coverage.svg)](https://codeclimate.com/github/Dhii/php-template/coverage) +[![Latest Stable Version](https://poser.pugx.org/dhii/php-template/version)](https://packagist.org/packages/dhii/php-template) + +A concrete PHP (PHTML) template implementation. + +[Dhii]: https://github.com/Dhii/dhii From dde354b4e6d0d8ae1d347586fa901b133fed9ca3 Mon Sep 17 00:00:00 2001 From: Anton Ukhanev Date: Wed, 8 Apr 2020 18:07:20 +0200 Subject: [PATCH 3/7] Add missing doc --- src/Template/PhpTemplate/FilePathTemplateFactory.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Template/PhpTemplate/FilePathTemplateFactory.php b/src/Template/PhpTemplate/FilePathTemplateFactory.php index 3b27472..8369b31 100644 --- a/src/Template/PhpTemplate/FilePathTemplateFactory.php +++ b/src/Template/PhpTemplate/FilePathTemplateFactory.php @@ -26,6 +26,11 @@ class FilePathTemplateFactory implements PathTemplateFactoryInterface */ protected $functions; + /** + * @param FilePhpEvaluatorFactoryInterface $evaluatorFactory A factory that creates PHP file evaluators. + * @param array $defaultContext A map of keys to values that will be available in template context by default. + * @param array $functions A map of keys to callables that will be available to templates by default. + */ public function __construct( FilePhpEvaluatorFactoryInterface $evaluatorFactory, array $defaultContext, @@ -46,4 +51,4 @@ public function fromPath(string $templatePath): TemplateInterface return $template; } -} \ No newline at end of file +} From c770f0eec47b5f25f85c20464ba9c5171e94105c Mon Sep 17 00:00:00 2001 From: Anton Ukhanev Date: Wed, 8 Apr 2020 18:52:27 +0200 Subject: [PATCH 4/7] Add docs to readme --- README.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/README.md b/README.md index 5a7eafb..d052b3b 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,85 @@ A concrete PHP (PHTML) template implementation. +## Details +This is an implementation of the [Dhii output renderer standard][dhii/output-renderer-interface]; +specifically, the template. It allows consuming file-based PHP templates using an abstract interface. +Now it's possible to outsource your rendering to standardized, stateless PHP template files, +and use them just like any other template, without knowing where the content comes from. + +Because this implementation is based on PHP files, it was decided to separate the concern +of rendering a template from the concern of evaluating a PHP file, because the latter +is useful on its own, and because it would make the template implementation thinner +and cleaner. + +### Usage +Below examples explain how a template factory could be configured, and used to produce a +standards-compliant template. Then that template is rendered with context. Please note the following: + +1. The file at path `template.php` is used to produce the output. +2. Context members are retrieved by `$c('key'')`. +3. It is possible to use the `uc` function with `$f('uc')`. +4. The default context member `time` is present in the template, even though it was not explicitly supplied +at render time. + +#### Configuration, usually in a service definition +```php +use Dhii\Output\PhpEvaluator\FilePhpEvaluatorFactory; +use Dhii\Output\Template\PhpTemplate\FilePathTemplateFactory; + +function () { + return new FilePathTemplateFactory( + new FilePhpEvaluatorFactory(), + [ // This will be available by default in all contexts of all templates made by this factory + 'time' => time(), // Let's assume it's 1586364371 + ], + [ // This will be available by default in all templates made by this factory + 'uc' => function (string $string) { + return strtoupper($string); + }, + ] + ); +}; +``` + +#### Consumption, usually somewhere in controller-level code +```php +use Dhii\Output\Template\PathTemplateFactoryInterface; +use Dhii\Output\Template\PhpTemplate\FilePathTemplateFactory; + +/* @var $fileTemplateFactory FilePathTemplateFactory */ +(function (PathTemplateFactoryInterface $factory) { + $template = $factory->fromPath('template.php'); + echo $template->render([ + 'username' => 'jcdenton', + 'password' => 'bionicman', + 'status' => 'defected', + ]); +})($fileTemplateFactory); // This is the factory created by above configuration +``` + +#### template.php +```php +/* + * template.php + */ +/* @var $c callable */ +/* @var $f callable */ +?> + +
+
+ +``` + +#### Resulting output +```html +1586364371 +jcdenton
+bionicman
+DEFECTED +``` + + [Dhii]: https://github.com/Dhii/dhii +[dhii/output-renderer-interface]: https://travis-ci.org/Dhii/output-renderer-interface From 37deb699885c1c324722d6ce8bbc190ba2c3e71e Mon Sep 17 00:00:00 2001 From: Anton Ukhanev Date: Tue, 7 Jul 2020 15:18:14 +0200 Subject: [PATCH 5/7] Remove extra quote --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d052b3b..b00fe2c 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Below examples explain how a template factory could be configured, and used to p standards-compliant template. Then that template is rendered with context. Please note the following: 1. The file at path `template.php` is used to produce the output. -2. Context members are retrieved by `$c('key'')`. +2. Context members are retrieved by `$c('key')`. 3. It is possible to use the `uc` function with `$f('uc')`. 4. The default context member `time` is present in the template, even though it was not explicitly supplied at render time. From b812a41e99e087399b9e86fa6d31e00848d9fb3e Mon Sep 17 00:00:00 2001 From: Anton Ukhanev Date: Tue, 7 Jul 2020 15:18:47 +0200 Subject: [PATCH 6/7] Add missing uses and types to example --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b00fe2c..c71539b 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,9 @@ at render time. ```php use Dhii\Output\PhpEvaluator\FilePhpEvaluatorFactory; use Dhii\Output\Template\PhpTemplate\FilePathTemplateFactory; +use Dhii\Output\Template\PathTemplateFactoryInterface; -function () { +function (): PathTemplateFactoryInterface { return new FilePathTemplateFactory( new FilePhpEvaluatorFactory(), [ // This will be available by default in all contexts of all templates made by this factory From 2ead413640e80d0a390b513e65de72bb78be274f Mon Sep 17 00:00:00 2001 From: Anton Ukhanev Date: Tue, 7 Jul 2020 15:19:02 +0200 Subject: [PATCH 7/7] Remove useless comment --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index c71539b..5e13957 100644 --- a/README.md +++ b/README.md @@ -67,9 +67,6 @@ use Dhii\Output\Template\PhpTemplate\FilePathTemplateFactory; #### template.php ```php -/* - * template.php - */ /* @var $c callable */ /* @var $f callable */ ?>