Skip to content

Commit

Permalink
Merge 6e6a816 into b940c06
Browse files Browse the repository at this point in the history
  • Loading branch information
othercorey committed Apr 4, 2020
2 parents b940c06 + 6e6a816 commit 5e9f496
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 43 deletions.
14 changes: 14 additions & 0 deletions src/Twig/Extension/ViewExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ class ViewExtension extends AbstractExtension
public function getFunctions(): array
{
return [
new TwigFunction(
'cell',
function ($context, string $name, array $data = [], array $options = []) {
return $context['_view']->cell($name, $data, $options);
},
['needs_context' => true, 'is_safe' => ['all']]
),
new TwigFunction(
'element',
function ($context, string $name, array $data = [], array $options = []) {
return $context['_view']->element($name, $data, $options);
},
['needs_context' => true, 'is_safe' => ['all']]
),
new TwigFunction(
'helper_*_*',
function ($context, $helper, $method, array $args = []) {
Expand Down
96 changes: 55 additions & 41 deletions src/View/TwigView.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use Jasny\Twig\DateExtension;
use Jasny\Twig\PcreExtension;
use Jasny\Twig\TextExtension;
use RuntimeException;
use Twig\Environment;
use Twig\Extension\DebugExtension;
use Twig\Extension\StringLoaderExtension;
Expand All @@ -47,6 +48,16 @@ class TwigView extends View
{
public const EXT = '.twig';

/**
* @var \Twig\Environment|null
*/
protected static $twig;

/**
* @var \Twig\Profiler\Profile|null
*/
protected static $profile;

/**
* Default config options.
*
Expand Down Expand Up @@ -82,16 +93,6 @@ class TwigView extends View
'.twig',
];

/**
* @var \Twig\Environment
*/
protected $twig;

/**
* @var \Twig\Profiler\Profile
*/
protected $profile;

/**
* Initialize view.
*
Expand All @@ -101,13 +102,16 @@ public function initialize(): void
{
parent::initialize();

$this->twig = $this->createEnvironment();
if (static::$twig === null) {
// Cache instance to avoid re-creating when rendering Cells
static::$twig = $this->createEnvironment();

$this->initializeTokenParser();
$this->initializeExtensions();
$this->initializeTokenParser();
$this->initializeExtensions();

if (Configure::read('debug') && Plugin::isLoaded('DebugKit')) {
$this->initializeProfiler();
if (Configure::read('debug') && Plugin::isLoaded('DebugKit')) {
$this->initializeProfiler();
}
}
}

Expand All @@ -118,17 +122,21 @@ public function initialize(): void
*/
public function getTwig(): Environment
{
return $this->twig;
if (static::$twig === null) {
throw new RuntimeException('Twig Environment instance not created.');
}

return static::$twig;
}

/**
* Gets Twig Profile if profiler enabled.
*
* @return \Twig\Profiler\Profile
* @return \Twig\Profiler\Profile|null
*/
public function getProfile(): Profile
public function getProfile(): ?Profile
{
return $this->profile;
return static::$profile;
}

/**
Expand Down Expand Up @@ -162,6 +170,7 @@ protected function createEnvironment(): Environment
}

$env = new Environment($this->createLoader(), $config);
// Must add before any templates are renders so can be updated in _render().
$env->addGlobal('_view', $this);

return $env;
Expand All @@ -174,8 +183,8 @@ protected function createEnvironment(): Environment
*/
protected function initializeTokenParser(): void
{
$this->twig->addTokenParser(new TokenParser\CellParser());
$this->twig->addTokenParser(new TokenParser\ElementParser());
$this->getTwig()->addTokenParser(new TokenParser\CellParser());
$this->getTwig()->addTokenParser(new TokenParser\ElementParser());
}

// phpcs:disable CakePHP.Commenting.FunctionComment.InvalidReturnVoid
Expand All @@ -187,28 +196,30 @@ protected function initializeTokenParser(): void
*/
protected function initializeExtensions(): void
{
$twig = $this->getTwig();

// Twig core extensions
$this->twig->addExtension(new StringLoaderExtension());
$this->twig->addExtension(new DebugExtension());
$twig->addExtension(new StringLoaderExtension());
$twig->addExtension(new DebugExtension());

// CakePHP bridging extensions
$this->twig->addExtension(new Extension\ArraysExtension());
$this->twig->addExtension(new Extension\BasicExtension());
$this->twig->addExtension(new Extension\ConfigureExtension());
$this->twig->addExtension(new Extension\I18nExtension());
$this->twig->addExtension(new Extension\InflectorExtension());
$this->twig->addExtension(new Extension\NumberExtension());
$this->twig->addExtension(new Extension\StringsExtension());
$this->twig->addExtension(new Extension\TimeExtension());
$this->twig->addExtension(new Extension\UtilsExtension());
$this->twig->addExtension(new Extension\ViewExtension());
$twig->addExtension(new Extension\ArraysExtension());
$twig->addExtension(new Extension\BasicExtension());
$twig->addExtension(new Extension\ConfigureExtension());
$twig->addExtension(new Extension\I18nExtension());
$twig->addExtension(new Extension\InflectorExtension());
$twig->addExtension(new Extension\NumberExtension());
$twig->addExtension(new Extension\StringsExtension());
$twig->addExtension(new Extension\TimeExtension());
$twig->addExtension(new Extension\UtilsExtension());
$twig->addExtension(new Extension\ViewExtension());

// Markdown extension
$markdownEngine = $this->getConfig('markdown.engine');
if ($markdownEngine instanceof MarkdownInterface) {
$this->twig->addExtension(new MarkdownExtension());
$twig->addExtension(new MarkdownExtension());

$this->twig->addRuntimeLoader(new class ($markdownEngine) implements RuntimeLoaderInterface {
$twig->addRuntimeLoader(new class ($markdownEngine) implements RuntimeLoaderInterface {
/**
* @var \Twig\Extra\Markdown\MarkdownInterface
*/
Expand Down Expand Up @@ -238,10 +249,10 @@ public function load($class)
}

// jasny/twig-extensions
$this->twig->addExtension(new DateExtension());
$this->twig->addExtension(new ArrayExtension());
$this->twig->addExtension(new PcreExtension());
$this->twig->addExtension(new TextExtension());
$twig->addExtension(new DateExtension());
$twig->addExtension(new ArrayExtension());
$twig->addExtension(new PcreExtension());
$twig->addExtension(new TextExtension());
}

// phpcs:enable
Expand All @@ -253,15 +264,18 @@ public function load($class)
*/
protected function initializeProfiler(): void
{
$this->profile = new Profile();
$this->twig->addExtension(new Extension\ProfilerExtension($this->profile));
static::$profile = new Profile();
$this->getTwig()->addExtension(new Extension\ProfilerExtension(static::$profile));
}

/**
* @inheritDoc
*/
protected function _render(string $templateFile, array $data = []): string
{
// Set _view for each render because Twig Environment is shared between views.
$this->getTwig()->addGlobal('_view', $this);

$data = array_merge(
empty($data) ? $this->viewVars : $data,
iterator_to_array($this->helpers()->getIterator())
Expand Down
24 changes: 23 additions & 1 deletion tests/TestCase/View/TwigViewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public function testRenderLayoutWithElements()
{
$output = $this->view->render('Blog/index');

$this->assertSame("blog_entry", $output);
$this->assertSame('<p>blog_entry</p>', $output);
}

/**
Expand All @@ -88,6 +88,28 @@ public function testRenderLayoutWithViewBlockAssignment()
$this->assertSame("main content\nextra content", $output);
}

/**
* Tests rendering a cell.
*
* @return void
*/
public function testRenderCell()
{
$output = $this->view->render('cell', false);
$this->assertSame('<b>10</b>', $output);
}

/**
* Tests that rendering a cell doesn't create a new Twig Environment.
*
* @return void
*/
public function testCellsShareTwig()
{
$cell = $this->view->cell('Test');
$this->assertSame($this->view->getTwig(), $cell->createView(AppView::class)->getTwig());
}

/**
* Tests a twig file that throws internal exception throw a Twig exception with message.
*
Expand Down
29 changes: 29 additions & 0 deletions tests/test_app/src/View/Cell/TestCell.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);

/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* Copyright (c) 2014 Cees-Jan Kiewiet
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 1.0.0
* @license https://opensource.org/licenses/mit-license.php MIT License
*/

namespace TestApp\View\Cell;

use Cake\View\Cell;

class TestCell extends Cell
{
public function display($number)
{
$this->set('testNumber', $number);
}
}
2 changes: 1 addition & 1 deletion tests/test_app/templates/Blog/index.twig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{% element 'blog_entry' %}
<p>{{ element('blog_entry') }}</p>
1 change: 1 addition & 0 deletions tests/test_app/templates/cell.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ cell('Test', data=[10]) }}
1 change: 1 addition & 0 deletions tests/test_app/templates/cell/Test/display.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<b>{{ testNumber }}</b>

0 comments on commit 5e9f496

Please sign in to comment.