diff --git a/.env.example b/.env.example index ac4eb2f..e181b10 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,6 @@ BASE_PATH=./ BUILD_ROOT_PATH=/app/ -PROJECT_NAME=me_library +PROJECT_NAME=dhii_twig-template PHP_BUILD_VERSION=7.2 PHP_TEST_VERSION=7.2 diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index a5e5aaf..26fc44d 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php-versions: ['7.2', '7.3', '7.4'] + php-versions: ['7.2', '7.3', '7.4', '8.0'] steps: - uses: actions/checkout@v2 diff --git a/.idea/php-project.iml b/.idea/php-project.iml index 995493d..4886a25 100644 --- a/.idea/php-project.iml +++ b/.idea/php-project.iml @@ -5,6 +5,7 @@ + @@ -60,6 +61,9 @@ + + + diff --git a/.idea/php.xml b/.idea/php.xml index f881867..72688c0 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -57,6 +57,9 @@ + + + @@ -187,7 +190,7 @@ - + diff --git a/composer.json b/composer.json index 80dc3a9..cbfd466 100644 --- a/composer.json +++ b/composer.json @@ -11,8 +11,9 @@ } ], "require": { - "php": "^7.2", - "dhii/output-renderer-interface": "^0.4" + "php": "^7.2 | ^8.0", + "dhii/output-renderer-interface": "^0.4", + "twig/twig": "^3.0" }, "require-dev": { "phpunit/phpunit": "^8.0 | ^9.0", diff --git a/composer.lock b/composer.lock index 8d9d833..338bb2f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1dfd20fa40210db6f4e0e33c6d18f040", + "content-hash": "dde9acfce478521545be4538c8900a02", "packages": [ { "name": "dhii/output-renderer-interface", @@ -107,6 +107,244 @@ "source": "https://github.com/Dhii/stringable-interface/tree/master" }, "time": "2017-01-23T15:08:20+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "fade6deebd931cfd7a544f68479405a6a08979a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fade6deebd931cfd7a544f68479405a6a08979a3", + "reference": "fade6deebd931cfd7a544f68479405a6a08979a3", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.21-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/main" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-26T13:35:45+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "401c9d9d3400c53a8f1a39425f0543406c137a43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/401c9d9d3400c53a8f1a39425f0543406c137a43", + "reference": "401c9d9d3400c53a8f1a39425f0543406c137a43", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.21-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/main" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-26T13:35:45+00:00" + }, + { + "name": "twig/twig", + "version": "3.x-dev", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "e3bca056f1331cf017893c2248d1d4951c165162" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/e3bca056f1331cf017893c2248d1d4951c165162", + "reference": "e3bca056f1331cf017893c2248d1d4951c165162", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/phpunit-bridge": "^4.4.9|^5.0.9" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/3.x" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2020-11-30T12:06:55+00:00" } ], "packages-dev": [ @@ -1687,12 +1925,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "51f5d93eedecd6f512562cb26d0f4d3abb52eb41" + "reference": "29f420d0b3844451a03d1d6e5e641bac88f27b07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/51f5d93eedecd6f512562cb26d0f4d3abb52eb41", - "reference": "51f5d93eedecd6f512562cb26d0f4d3abb52eb41", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/29f420d0b3844451a03d1d6e5e641bac88f27b07", + "reference": "29f420d0b3844451a03d1d6e5e641bac88f27b07", "shasum": "" }, "require": { @@ -1776,7 +2014,7 @@ "type": "github" } ], - "time": "2020-12-23T06:00:38+00:00" + "time": "2020-12-24T12:25:02+00:00" }, { "name": "psr/container", @@ -2829,86 +3067,6 @@ ], "time": "2020-12-18T08:03:24+00:00" }, - { - "name": "symfony/polyfill-ctype", - "version": "dev-main", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "fade6deebd931cfd7a544f68479405a6a08979a3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fade6deebd931cfd7a544f68479405a6a08979a3", - "reference": "fade6deebd931cfd7a544f68479405a6a08979a3", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "default-branch": true, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.21-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/main" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-26T13:35:45+00:00" - }, { "name": "symfony/polyfill-intl-grapheme", "version": "dev-main", @@ -3076,87 +3234,6 @@ ], "time": "2020-10-26T13:35:45+00:00" }, - { - "name": "symfony/polyfill-mbstring", - "version": "dev-main", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "401c9d9d3400c53a8f1a39425f0543406c137a43" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/401c9d9d3400c53a8f1a39425f0543406c137a43", - "reference": "401c9d9d3400c53a8f1a39425f0543406c137a43", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "default-branch": true, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.21-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/main" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-26T13:35:45+00:00" - }, { "name": "symfony/polyfill-php73", "version": "dev-main", @@ -3803,7 +3880,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.2" + "php": "^7.2 | ^8.0" }, "platform-dev": [], "plugin-api-version": "2.0.0" diff --git a/src/Exception/TemplateRenderException.php b/src/Exception/TemplateRenderException.php new file mode 100644 index 0000000..9903901 --- /dev/null +++ b/src/Exception/TemplateRenderException.php @@ -0,0 +1,56 @@ +renderer = $renderer; + $this->context = $context; + } + + /** + * @inheritDoc + */ + public function getContext() + { + return $this->context; + } + + /** + * @inheritDoc + */ + public function getRenderer() + { + return $this->renderer; + } +} diff --git a/src/FileTemplate.php b/src/FileTemplate.php new file mode 100644 index 0000000..2b589df --- /dev/null +++ b/src/FileTemplate.php @@ -0,0 +1,74 @@ +twigTemplate = $twigTemplate; + } + + /** + * @inheritDoc + */ + public function render($context = null) + { + $context = $this->normalizeContext($context); + + try { + return $this->twigTemplate->render($context); + } catch (Exception $e) { + throw new TemplateRenderException($this, $context, $this->__('Could not render template'), 0, $e); + } + } + + /** + * Normalizes context to a canonical representation. + * + * @param array|iterable|object $context The context to normalize. + * @return array The canonical representation of the context. + * @throws InvalidArgumentException If context cannot be normalized. + */ + protected function normalizeContext($context): array + { + if ($context instanceof Traversable) { + $context = iterator_to_array($context); + } + + if (!is_array($context)) { + throw new InvalidArgumentException($this->__('Context must be an array; %1$s given', [gettype($context)])); + } + + return $context; + } + + /** + * Translates a string and interpolates values. + * + * The values in the string may be specified using the {@see sprintf()} style. + * + * @param string $string The string to translate. + * @param array $placeholders Numeric array. The values to replace placeholders in the string with. + * + * @throws Exception If problem translating. + * + * @return string The translated string, with placeholders replaced. + */ + protected function __(string $string, $placeholders = []): string + { + return vsprintf($string, $placeholders); + } +} diff --git a/src/FileTemplateFactory.php b/src/FileTemplateFactory.php new file mode 100644 index 0000000..b8fa96a --- /dev/null +++ b/src/FileTemplateFactory.php @@ -0,0 +1,36 @@ +environment = $environment; + } + + /** + * @inheritDoc + */ + public function fromPath(string $templatePath): TemplateInterface + { + $twigTemplate = $this->environment->load($templatePath); + $template = new FileTemplate($twigTemplate); + + return $template; + } +} diff --git a/tests/functional/FileTemplateFactoryTest.php b/tests/functional/FileTemplateFactoryTest.php new file mode 100644 index 0000000..4645799 --- /dev/null +++ b/tests/functional/FileTemplateFactoryTest.php @@ -0,0 +1,73 @@ +getMockBuilder(Subject::class) + ->enableProxyingToOriginalMethods() + ->setConstructorArgs([$environment]) + ->getMock(); + + return $mock; + } + + public function testTemplate() + { + { + $env = $this->getEnvironment(); + $templatePath = self::TEMPLATE_PATH_SIMPLE; + $message = uniqid('message'); + $data = [ + 'message' => $message, + ]; + $subject = $this->createSubject($env); + } + + { + $template = $subject->fromPath($templatePath); + $result = $template->render($data); + $this->assertEquals($this->renderTemplate($templatePath, $data), $result); + } + } + + protected function renderTemplate(string $filePath, array $context): string + { + $env = $this->getEnvironment(); + $template = $env->load($filePath); + $output = $template->render($context); + + return $output; + } + + protected function getEnvironment(): Environment + { + if (!($this->environment instanceof Environment)) { + $loader = new FilesystemLoader( + [ + '__main__' => '//', + ], '//' + ); + $this->environment = new Environment($loader, []); + } + + return $this->environment; + } +} diff --git a/tests/stub/simple.twig b/tests/stub/simple.twig new file mode 100644 index 0000000..d0edeb9 --- /dev/null +++ b/tests/stub/simple.twig @@ -0,0 +1 @@ +

{{ message }}