summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--composer.json1
-rw-r--r--config/app.php1
-rw-r--r--includes/engelsystem.php2
-rw-r--r--includes/pages/guest_credits.php2
-rw-r--r--includes/pages/user_shifts.php2
-rw-r--r--src/Application.php1
-rw-r--r--src/Middleware/LegacyMiddleware.php2
-rw-r--r--src/Renderer/TwigEngine.php41
-rw-r--r--src/Renderer/TwigLoader.php26
-rw-r--r--src/Renderer/TwigServiceProvider.php31
-rw-r--r--src/helpers.php4
-rw-r--r--templates/layout.html62
-rw-r--r--templates/layouts/app.twig80
-rw-r--r--templates/layouts/maintenance.html (renamed from templates/maintenance.html)0
-rw-r--r--templates/pages/credits.html (renamed from templates/guest_credits.html)18
-rw-r--r--templates/pages/user-shifts.html (renamed from templates/user_shifts.html)0
-rw-r--r--tests/Unit/ApplicationTest.php1
-rw-r--r--tests/Unit/Renderer/TwigEngineTest.php60
-rw-r--r--tests/Unit/Renderer/TwigLoaderTest.php31
-rw-r--r--tests/Unit/Renderer/TwigServiceProviderTest.php63
20 files changed, 351 insertions, 77 deletions
diff --git a/composer.json b/composer.json
index f38bb972..0e6ee17d 100644
--- a/composer.json
+++ b/composer.json
@@ -29,6 +29,7 @@
"symfony/http-foundation": "^3.3",
"symfony/psr-http-message-bridge": "^1.0",
"twbs/bootstrap": "^3.3",
+ "twig/twig": "^2.5",
"zendframework/zend-diactoros": "^1.7"
},
"require-dev": {
diff --git a/config/app.php b/config/app.php
index 9af35eb4..13d4d22b 100644
--- a/config/app.php
+++ b/config/app.php
@@ -10,6 +10,7 @@ return [
\Engelsystem\Config\ConfigServiceProvider::class,
\Engelsystem\Http\UrlGeneratorServiceProvider::class,
\Engelsystem\Renderer\RendererServiceProvider::class,
+ \Engelsystem\Renderer\TwigServiceProvider::class,
\Engelsystem\Database\DatabaseServiceProvider::class,
\Engelsystem\Http\RequestServiceProvider::class,
\Engelsystem\Http\SessionServiceProvider::class,
diff --git a/includes/engelsystem.php b/includes/engelsystem.php
index f7d813c5..eb5b220a 100644
--- a/includes/engelsystem.php
+++ b/includes/engelsystem.php
@@ -16,7 +16,7 @@ require __DIR__ . '/includes.php';
* Check for maintenance
*/
if ($app->get('config')->get('maintenance')) {
- echo file_get_contents(__DIR__ . '/../templates/maintenance.html');
+ echo file_get_contents(__DIR__ . '/../templates/layouts/maintenance.html');
die();
}
diff --git a/includes/pages/guest_credits.php b/includes/pages/guest_credits.php
index db86132d..ecfa8f7c 100644
--- a/includes/pages/guest_credits.php
+++ b/includes/pages/guest_credits.php
@@ -13,5 +13,5 @@ function credits_title()
*/
function guest_credits()
{
- return view(__DIR__ . '/../../templates/guest_credits.html');
+ return view(__DIR__ . '/../../templates/pages/credits.html');
}
diff --git a/includes/pages/user_shifts.php b/includes/pages/user_shifts.php
index a620d081..67f6785f 100644
--- a/includes/pages/user_shifts.php
+++ b/includes/pages/user_shifts.php
@@ -224,7 +224,7 @@ function view_user_shifts()
return page([
div('col-md-12', [
msg(),
- view(__DIR__ . '/../../templates/user_shifts.html', [
+ view(__DIR__ . '/../../templates/pages/user-shifts.html', [
'title' => shifts_title(),
'room_select' => make_select($rooms, $shiftsFilter->getRooms(), 'rooms', _('Rooms')),
'start_select' => html_select_key(
diff --git a/src/Application.php b/src/Application.php
index 6644a6cf..86397a2c 100644
--- a/src/Application.php
+++ b/src/Application.php
@@ -107,6 +107,7 @@ class Application extends Container
$this->instance('path', $appPath);
$this->instance('path.config', $appPath . DIRECTORY_SEPARATOR . 'config');
$this->instance('path.lang', $appPath . DIRECTORY_SEPARATOR . 'locale');
+ $this->instance('path.views', $appPath . DIRECTORY_SEPARATOR . 'templates');
}
/**
diff --git a/src/Middleware/LegacyMiddleware.php b/src/Middleware/LegacyMiddleware.php
index 276fb3ee..37ae9331 100644
--- a/src/Middleware/LegacyMiddleware.php
+++ b/src/Middleware/LegacyMiddleware.php
@@ -283,7 +283,7 @@ class LegacyMiddleware implements MiddlewareInterface
$content = info($content, true);
}
- return response(view(__DIR__ . '/../../templates/layout.html', [
+ return response(view('layouts/app', [
'theme' => isset($user) ? $user['color'] : config('theme'),
'title' => $title,
'atom_link' => ($page == 'news' || $page == 'user_meetings')
diff --git a/src/Renderer/TwigEngine.php b/src/Renderer/TwigEngine.php
new file mode 100644
index 00000000..55a2e299
--- /dev/null
+++ b/src/Renderer/TwigEngine.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Engelsystem\Renderer;
+
+use Twig_Environment as Twig;
+use Twig_Error_Loader as LoaderError;
+use Twig_Error_Runtime as RuntimeError;
+use Twig_Error_Syntax as SyntaxError;
+
+class TwigEngine implements EngineInterface
+{
+ /** @var Twig */
+ protected $twig;
+
+ public function __construct(Twig $twig)
+ {
+ $this->twig = $twig;
+ }
+
+ /**
+ * Render a twig template
+ *
+ * @param string $path
+ * @param array $data
+ * @return string
+ * @throws LoaderError|RuntimeError|SyntaxError
+ */
+ public function get($path, $data = [])
+ {
+ return $this->twig->render($path, $data);
+ }
+
+ /**
+ * @param string $path
+ * @return bool
+ */
+ public function canRender($path)
+ {
+ return $this->twig->getLoader()->exists($path);
+ }
+}
diff --git a/src/Renderer/TwigLoader.php b/src/Renderer/TwigLoader.php
new file mode 100644
index 00000000..154e6dbb
--- /dev/null
+++ b/src/Renderer/TwigLoader.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Engelsystem\Renderer;
+
+use Twig_Error_Loader;
+use Twig_Loader_Filesystem as FilesystemLoader;
+
+class TwigLoader extends FilesystemLoader
+{
+ /**
+ * @param string $name
+ * @param bool $throw
+ * @return false|string
+ * @throws Twig_Error_Loader
+ */
+ public function findTemplate($name, $throw = true)
+ {
+ $extension = '.twig';
+ $extensionLength = strlen($extension);
+ if (substr($name, -$extensionLength, $extensionLength) !== $extension) {
+ $name .= $extension;
+ }
+
+ return parent::findTemplate($name, $throw);
+ }
+}
diff --git a/src/Renderer/TwigServiceProvider.php b/src/Renderer/TwigServiceProvider.php
new file mode 100644
index 00000000..23810863
--- /dev/null
+++ b/src/Renderer/TwigServiceProvider.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Engelsystem\Renderer;
+
+use Engelsystem\Container\ServiceProvider;
+use Twig_Environment as Twig;
+use Twig_LoaderInterface as TwigLoaderInterface;
+
+class TwigServiceProvider extends ServiceProvider
+{
+ public function register()
+ {
+ $this->registerTwigEngine();
+ }
+
+ protected function registerTwigEngine()
+ {
+ $viewsPath = $this->app->get('path.views');
+
+ $twigLoader = $this->app->make(TwigLoader::class, ['paths' => $viewsPath]);
+ $this->app->instance(TwigLoader::class, $twigLoader);
+ $this->app->instance(TwigLoaderInterface::class, $twigLoader);
+
+ $twig = $this->app->make(Twig::class);
+ $this->app->instance(Twig::class, $twig);
+
+ $twigEngine = $this->app->make(TwigEngine::class);
+ $this->app->instance('renderer.twigEngine', $twigEngine);
+ $this->app->tag('renderer.twigEngine', ['renderer.engine']);
+ }
+}
diff --git a/src/helpers.php b/src/helpers.php
index a90b2462..336f81fe 100644
--- a/src/helpers.php
+++ b/src/helpers.php
@@ -5,8 +5,8 @@ use Engelsystem\Application;
use Engelsystem\Config\Config;
use Engelsystem\Http\Request;
use Engelsystem\Http\Response;
-use Engelsystem\Renderer\Renderer;
use Engelsystem\Http\UrlGenerator;
+use Engelsystem\Renderer\Renderer;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
/**
@@ -139,7 +139,7 @@ function url($path = null, $parameters = [])
* @param mixed[] $data
* @return Renderer|string
*/
-function view($template = null, $data = null)
+function view($template = null, $data = [])
{
$renderer = app('renderer');
diff --git a/templates/layout.html b/templates/layout.html
deleted file mode 100644
index 12a91086..00000000
--- a/templates/layout.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>%title% - Engelsystem</title>
- <meta charset="UTF-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" type="text/css" href="css/theme%theme%.css"/>
- <link rel="stylesheet" type="text/css" href="vendor/icomoon/style.css"/>
- <link rel="stylesheet" type="text/css" href="vendor/bootstrap-datepicker-1.7.1/css/bootstrap-datepicker3.min.css"/>
- <script type="text/javascript" src="vendor/jquery-2.1.1.min.js"></script>
- <script type="text/javascript" src="vendor/jquery-ui.min.js"></script>
- %atom_link%
-</head>
-<body>
-<div class="navbar navbar-default navbar-fixed-top">
- <div class="container-fluid">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle collapsed"
- data-toggle="collapse" data-target="#navbar-collapse-1">
- <span class="sr-only">Toggle navigation</span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- <a class="navbar-brand" href="%start_page_url%">
- <span class="icon-icon_angel"></span> <strong class="visible-lg-inline">ENGELSYSTEM</strong>
- </a>
- </div>
- <div class="collapse navbar-collapse" id="navbar-collapse-1">%menu% %header_toolbar%</div>
- </div>
-</div>
-<div class="container-fluid">
- <div class="row">%content%</div>
- <div class="row" id="footer">
- <div class="col-md-12">
- <hr/>
- <div class="text-center footer" style="margin-bottom: 10px;">
- %event_info%
- <a href="%faq_url%">FAQ</a>
- · <a href="%contact_email%"><span class="glyphicon glyphicon-envelope"></span> Contact</a>
- · <a href="https://github.com/engelsystem/engelsystem/issues">Bugs / Features</a>
- · <a href="https://github.com/engelsystem/engelsystem/">Development Platform</a>
- · <a href="%credits_url%">Credits</a>
- </div>
- </div>
- </div>
-</div>
-<script type="text/javascript" src="vendor/bootstrap/js/bootstrap.min.js"></script>
-<script type="text/javascript" src="vendor/bootstrap-datepicker-1.7.1/js/bootstrap-datepicker.min.js"></script>
-<script type="text/javascript" src="vendor/bootstrap-datepicker-1.7.1/locales/bootstrap-datepicker.de.min.js"></script>
-<script type="text/javascript" src="vendor/Chart.min.js"></script>
-<script type="text/javascript" src="js/forms.js"></script>
-<script type="text/javascript" src="vendor/moment-with-locales.min.js"></script>
-<script type="text/javascript">
- $(function () {
- moment.locale("%locale%");
- });
-</script>
-<script type="text/javascript" src="js/moment-countdown.js"></script>
-<script type="text/javascript" src="js/sticky-headers.js"></script>
-</body>
-</html>
diff --git a/templates/layouts/app.twig b/templates/layouts/app.twig
new file mode 100644
index 00000000..6b6bd16f
--- /dev/null
+++ b/templates/layouts/app.twig
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<head>
+ {% block head %}
+ <title>{% block title %}{{ title }}{% endblock %} - Engelsystem</title>
+ <meta charset="UTF-8"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="stylesheet" type="text/css" href="css/theme{{ theme }}.css"/>
+ <link rel="stylesheet" type="text/css" href="vendor/icomoon/style.css"/>
+ <link rel="stylesheet" type="text/css" href="vendor/bootstrap-datepicker-1.7.1/css/bootstrap-datepicker3.min.css"/>
+ <script type="text/javascript" src="vendor/jquery-2.1.1.min.js"></script>
+ <script type="text/javascript" src="vendor/jquery-ui.min.js"></script>
+ {{ atom_link|raw }}
+ {% endblock %}
+</head>
+<body>
+
+{% block body %}
+ <div class="navbar navbar-default navbar-fixed-top">
+ {% block header %}
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle collapsed"
+ data-toggle="collapse" data-target="#navbar-collapse-1">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="{{ start_page_url }}">
+ <span class="icon-icon_angel"></span> <strong class="visible-lg-inline">ENGELSYSTEM</strong>
+ </a>
+ </div>
+
+ {% block navbar %}
+ <div class="collapse navbar-collapse"
+ id="navbar-collapse-1">{{ menu|raw }} {{ header_toolbar|raw }}</div>
+ {% endblock %}
+ </div>
+ {% endblock %}
+ </div>
+
+ <div class="container-fluid">
+ <div class="row">{% block content %}{{ content|raw }}{% endblock %}</div>
+ <div class="row" id="footer">
+ {% block footer %}
+ <div class="col-md-12">
+ <hr/>
+ <div class="text-center footer" style="margin-bottom: 10px;">
+ {% block eventinfo %}
+ {{ event_info|raw }}
+ {% endblock %}
+ <a href="{{ faq_url }}">FAQ</a>
+ · <a href="{{ contact_email }}"><span class="glyphicon glyphicon-envelope"></span> Contact</a>
+ · <a href="https://github.com/engelsystem/engelsystem/issues">Bugs / Features</a>
+ · <a href="https://github.com/engelsystem/engelsystem/">Development Platform</a>
+ · <a href="{{ credits_url }}">Credits</a>
+ </div>
+ </div>
+ {% endblock %}
+ </div>
+ </div>
+
+ <script type="text/javascript" src="vendor/bootstrap/js/bootstrap.min.js"></script>
+ <script type="text/javascript" src="vendor/bootstrap-datepicker-1.7.1/js/bootstrap-datepicker.min.js"></script>
+ <script type="text/javascript" src="vendor/bootstrap-datepicker-1.7.1/locales/bootstrap-datepicker.de.min.js"></script>
+ <script type="text/javascript" src="vendor/Chart.min.js"></script>
+ <script type="text/javascript" src="js/forms.js"></script>
+ <script type="text/javascript" src="vendor/moment-with-locales.min.js"></script>
+ <script type="text/javascript">
+ $(function () {
+ moment.locale("{{ locale|escape('js') }}");
+ });
+ </script>
+ <script type="text/javascript" src="js/moment-countdown.js"></script>
+ <script type="text/javascript" src="js/sticky-headers.js"></script>
+{% endblock %}
+
+</body>
+</html>
diff --git a/templates/maintenance.html b/templates/layouts/maintenance.html
index bd73bd74..bd73bd74 100644
--- a/templates/maintenance.html
+++ b/templates/layouts/maintenance.html
diff --git a/templates/guest_credits.html b/templates/pages/credits.html
index db7fac57..4e247113 100644
--- a/templates/guest_credits.html
+++ b/templates/pages/credits.html
@@ -6,15 +6,15 @@
<p>
The original system was written by <a href="https://github.com/cookieBerlin/engelsystem">cookie</a>.
It was then completely rewritten and enhanced by
- <a href="http://notrademark.de/">msquare</a> (maintainer),
- <a href="http://myigel.name/">MyIgel</a>,
- <a href="http://mortzu.de/">mortzu</a>,
- <a href="http://jplitza.de/">jplitza</a> and
- gnomus.
+ <a href="https://notrademark.de">msquare</a> (maintainer),
+ <a href="https://myigel.name">MyIgel</a>,
+ <a href="https://mortzu.de">mortzu</a>,
+ <a href="https://jplitza.de">jplitza</a> and
+ <a href="https://github.com/gnomus">gnomus</a>.
</p>
<p>
- Please look at the <a href="https://github.com/engelsystem/engelsystem/graphs/contributors">contributor
- list on github</a> for a more complete version.
+ Please look at the <a href="https://github.com/engelsystem/engelsystem/graphs/contributors">
+ contributor list on github</a> for a more complete version.
</p>
</div>
<div class="col-md-4">
@@ -22,8 +22,8 @@
<p>
Webspace, development platform and domain on <a href="https://engelsystem.de">engelsystem.de</a>
is currently provided by <a href="https://www.wybt.net/">would you buy this?</a> (ichdasich)
- and adminstrated by <a href="http://mortzu.de/">mortzu</a>,
- <a href="http://derf.homelinux.org/">derf</a> and ichdasich.
+ and adminstrated by <a href="https://mortzu.de">mortzu</a>,
+ <a href="http://derf.homelinux.org">derf</a> and ichdasich.
</p>
</div>
<div class="col-md-4">
diff --git a/templates/user_shifts.html b/templates/pages/user-shifts.html
index e137210c..e137210c 100644
--- a/templates/user_shifts.html
+++ b/templates/pages/user-shifts.html
diff --git a/tests/Unit/ApplicationTest.php b/tests/Unit/ApplicationTest.php
index 866eb957..012226b2 100644
--- a/tests/Unit/ApplicationTest.php
+++ b/tests/Unit/ApplicationTest.php
@@ -48,6 +48,7 @@ class ApplicationTest extends TestCase
$this->assertTrue($app->has('path'));
$this->assertTrue($app->has('path.config'));
$this->assertTrue($app->has('path.lang'));
+ $this->assertTrue($app->has('path.views'));
$this->assertEquals(realpath('.'), $app->path());
$this->assertEquals(realpath('.') . '/config', $app->get('path.config'));
diff --git a/tests/Unit/Renderer/TwigEngineTest.php b/tests/Unit/Renderer/TwigEngineTest.php
new file mode 100644
index 00000000..9d0618f1
--- /dev/null
+++ b/tests/Unit/Renderer/TwigEngineTest.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Engelsystem\Test\Unit\Renderer;
+
+use Engelsystem\Renderer\TwigEngine;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+use Twig_Environment as Twig;
+use Twig_LoaderInterface as LoaderInterface;
+
+class TwigEngineTest extends TestCase
+{
+ /**
+ * @covers \Engelsystem\Renderer\TwigEngine::__construct
+ * @covers \Engelsystem\Renderer\TwigEngine::get
+ */
+ public function testGet()
+ {
+ /** @var Twig|MockObject $twig */
+ $twig = $this->createMock(Twig::class);
+
+ $path = 'foo.twig';
+ $data = ['lorem' => 'ipsum'];
+
+ $twig->expects($this->once())
+ ->method('render')
+ ->with($path, $data)
+ ->willReturn('LoremIpsum!');
+
+ $engine = new TwigEngine($twig);
+ $return = $engine->get($path, $data);
+ $this->assertEquals('LoremIpsum!', $return);
+ }
+
+
+ /**
+ * @covers \Engelsystem\Renderer\TwigEngine::canRender
+ */
+ public function testCanRender()
+ {
+ /** @var Twig|MockObject $twig */
+ $twig = $this->createMock(Twig::class);
+ /** @var LoaderInterface|MockObject $loader */
+ $loader = $this->getMockForAbstractClass(LoaderInterface::class);
+
+ $path = 'foo.twig';
+
+ $twig->expects($this->once())
+ ->method('getLoader')
+ ->willReturn($loader);
+ $loader->expects($this->once())
+ ->method('exists')
+ ->with($path)
+ ->willReturn(true);
+
+ $engine = new TwigEngine($twig);
+ $return = $engine->canRender($path);
+ $this->assertTrue($return);
+ }
+}
diff --git a/tests/Unit/Renderer/TwigLoaderTest.php b/tests/Unit/Renderer/TwigLoaderTest.php
new file mode 100644
index 00000000..e6867643
--- /dev/null
+++ b/tests/Unit/Renderer/TwigLoaderTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Engelsystem\Test\Unit\Renderer;
+
+use Engelsystem\Renderer\TwigLoader;
+use PHPUnit\Framework\TestCase;
+use ReflectionClass as Reflection;
+
+class TwigLoaderTest extends TestCase
+{
+ /**
+ * @covers \Engelsystem\Renderer\TwigLoader::findTemplate
+ */
+ public function testFindTemplate()
+ {
+ $loader = new TwigLoader();
+
+ $reflection = new Reflection(get_class($loader));
+ $property = $reflection->getProperty('cache');
+ $property->setAccessible(true);
+
+ $realPath = __DIR__ . '/Stub/foo.twig';
+ $property->setValue($loader, ['Stub/foo.twig' => $realPath]);
+
+ $return = $loader->findTemplate('Stub/foo.twig');
+ $this->assertEquals($realPath, $return);
+
+ $return = $loader->findTemplate('Stub/foo');
+ $this->assertEquals($realPath, $return);
+ }
+}
diff --git a/tests/Unit/Renderer/TwigServiceProviderTest.php b/tests/Unit/Renderer/TwigServiceProviderTest.php
new file mode 100644
index 00000000..ede6fae4
--- /dev/null
+++ b/tests/Unit/Renderer/TwigServiceProviderTest.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Engelsystem\Test\Unit\Renderer;
+
+use Engelsystem\Renderer\TwigEngine;
+use Engelsystem\Renderer\TwigLoader;
+use Engelsystem\Renderer\TwigServiceProvider;
+use Engelsystem\Test\Unit\ServiceProviderTest;
+use PHPUnit\Framework\MockObject\MockObject;
+use Twig_Environment as Twig;
+use Twig_LoaderInterface as TwigLoaderInterface;
+
+class TwigServiceProviderTest extends ServiceProviderTest
+{
+ /**
+ * @covers \Engelsystem\Renderer\TwigServiceProvider::register
+ * @covers \Engelsystem\Renderer\TwigServiceProvider::registerTwigEngine
+ */
+ public function testRegister()
+ {
+ /** @var TwigEngine|MockObject $htmlEngine */
+ $twigEngine = $this->createMock(TwigEngine::class);
+ /** @var TwigLoader|MockObject $twigLoader */
+ $twigLoader = $this->createMock(TwigLoader::class);
+ /** @var Twig|MockObject $twig */
+ $twig = $this->createMock(Twig::class);
+
+ $app = $this->getApp(['make', 'instance', 'tag', 'get']);
+
+ $viewsPath = __DIR__ . '/Stub';
+
+ $app->expects($this->exactly(3))
+ ->method('make')
+ ->withConsecutive(
+ [TwigLoader::class, ['paths' => $viewsPath]],
+ [Twig::class],
+ [TwigEngine::class]
+ )->willReturnOnConsecutiveCalls(
+ $twigLoader,
+ $twig,
+ $twigEngine
+ );
+
+ $app->expects($this->exactly(4))
+ ->method('instance')
+ ->withConsecutive(
+ [TwigLoader::class, $twigLoader],
+ [TwigLoaderInterface::class, $twigLoader],
+ [Twig::class, $twig],
+ ['renderer.twigEngine', $twigEngine]
+ );
+
+ $app->expects($this->once())
+ ->method('get')
+ ->with('path.views')
+ ->willReturn($viewsPath);
+
+ $this->setExpects($app, 'tag', ['renderer.twigEngine', ['renderer.engine']]);
+
+ $serviceProvider = new TwigServiceProvider($app);
+ $serviceProvider->register();
+ }
+}