Skip to content

Commit

Permalink
added bridge for Latte 3
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed May 17, 2022
1 parent 8bf7455 commit 7a59a77
Show file tree
Hide file tree
Showing 20 changed files with 387 additions and 11 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/coding-style.yml
Expand Up @@ -10,7 +10,7 @@ jobs:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
php-version: 7.2
php-version: 8.0
coverage: none

- run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress
Expand All @@ -24,7 +24,7 @@ jobs:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
php-version: 7.4
php-version: 8.0
coverage: none

- run: composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Expand Up @@ -52,7 +52,7 @@ jobs:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
php-version: 7.4
php-version: 8.0
coverage: none

- run: composer install --no-progress --prefer-dist
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Expand Up @@ -22,7 +22,7 @@
"require-dev": {
"nette/tester": "^2.0",
"nette/di": "^v3.0",
"latte/latte": "^2.10",
"latte/latte": "^2.11 || ^3.0",
"tracy/tracy": "^2.4",
"phpstan/phpstan": "^0.12"
},
Expand Down
68 changes: 68 additions & 0 deletions src/Bridges/CacheLatte/CacheExtension.php
@@ -0,0 +1,68 @@
<?php

/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/

declare(strict_types=1);

namespace Nette\Bridges\CacheLatte;

use Latte;
use Latte\Compiler\Nodes\AuxiliaryNode;
use Latte\Compiler\Nodes\TemplateNode;
use Latte\Compiler\Tag;
use Latte\Engine;
use Nette\Caching\Storage;


/**
* Latte v3 extension for Nette Caching
*/
final class CacheExtension extends Latte\Extension
{
private bool $used;
private Storage $storage;


public function __construct(Storage $storage)
{
$this->storage = $storage;
}


public function beforeCompile(Latte\Engine $engine): void
{
$this->used = false;
}


public function getTags(): array
{
return [
'cache' => function (Tag $tag): \Generator {
$this->used = true;
return Nodes\CacheNode::create($tag);
},
];
}


public function getPasses(): array
{
return [
'cacheInitialization' => function (TemplateNode $node): void {
if ($this->used) {
$node->head->append(new AuxiliaryNode(fn() => Nodes\CacheNode::class . '::initRuntime($this);'));
}
},
];
}


public function beforeRender(Engine $engine): void
{
$engine->addProvider('cacheStorage', $this->storage);
}
}
2 changes: 1 addition & 1 deletion src/Bridges/CacheLatte/CacheMacro.php
Expand Up @@ -15,7 +15,7 @@


/**
* Macro {cache} ... {/cache}
* Macro {cache} ... {/cache} for Latte v2
*/
final class CacheMacro implements Latte\IMacro
{
Expand Down
149 changes: 149 additions & 0 deletions src/Bridges/CacheLatte/Nodes/CacheNode.php
@@ -0,0 +1,149 @@
<?php

/**
* This file is part of the Latte (https://latte.nette.org)
* Copyright (c) 2008 David Grudl (https://davidgrudl.com)
*/

declare(strict_types=1);

namespace Nette\Bridges\CacheLatte\Nodes;

use Latte;
use Latte\Compiler\Nodes\AreaNode;
use Latte\Compiler\Nodes\Php\Expression\ArrayNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\Position;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;
use Nette;
use Nette\Caching\Cache;


/**
* {cache} ... {/cache}
*/
class CacheNode extends StatementNode
{
public ArrayNode $args;
public AreaNode $content;
public ?Position $endLine;


/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
public static function create(Tag $tag): \Generator
{
$node = new static;
$node->args = $tag->parser->parseArguments();
[$node->content, $endTag] = yield;
$node->endLine = $endTag?->position;
return $node;
}


public function print(PrintContext $context): string
{
return $context->format(
<<<'XX'
if (Nette\Bridges\CacheLatte\Nodes\CacheNode::createCache($this->global->cacheStorage, %dump, $this->global->cacheStack, %node?)) %line
try {
%node
Nette\Bridges\CacheLatte\Nodes\CacheNode::endCache($this->global->cacheStack) %line;
} catch (\Throwable $ʟ_e) {
Nette\Bridges\CacheLatte\Nodes\CacheNode::rollback($this->global->cacheStack); throw $ʟ_e;
}
XX,
Nette\Utils\Random::generate(),
$this->args,
$this->position,
$this->content,
$this->endLine,
);
}


public function &getIterator(): \Generator
{
yield $this->args;
yield $this->content;
}


/********************* run-time helpers ****************d*g**/


public static function initRuntime(Latte\Runtime\Template $template): void
{
if (!empty($template->global->cacheStack)) {
$file = (new \ReflectionClass($template))->getFileName();
if (@is_file($file)) { // @ - may trigger error
end($template->global->cacheStack)->dependencies[Cache::Files][] = $file;
}
}
}


/**
* Starts the output cache. Returns Nette\Caching\OutputHelper object if buffering was started.
* @return Nette\Caching\OutputHelper|\stdClass
*/
public static function createCache(
Nette\Caching\Storage $cacheStorage,
string $key,
?array &$parents,
?array $args = null,
) {
if ($args) {
if (array_key_exists('if', $args) && !$args['if']) {
return $parents[] = new \stdClass;
}

$key = array_merge([$key], array_intersect_key($args, range(0, count($args))));
}

if ($parents) {
end($parents)->dependencies[Cache::Items][] = $key;
}

$cache = new Cache($cacheStorage, 'Nette.Templating.Cache');
if ($helper = $cache->capture($key)) {
$parents[] = $helper;

if (isset($args['dependencies'])) {
$args += $args['dependencies']();
}

$helper->dependencies[Cache::Tags] = $args['tags'] ?? null;
$helper->dependencies[Cache::Expire] = $args['expiration'] ?? $args['expire'] ?? '+ 7 days';
}

return $helper;
}


/**
* Ends the output cache.
* @param Nette\Caching\OutputHelper[] $parents
*/
public static function endCache(array &$parents): void
{
$helper = array_pop($parents);
if ($helper instanceof Nette\Caching\OutputHelper) {
$helper->end();
}
}


/**
* @param Nette\Caching\OutputHelper[] $parents
*/
public static function rollback(array &$parents): void
{
$helper = array_pop($parents);
if ($helper instanceof Nette\Caching\OutputHelper) {
$helper->rollback();
}
}
}
Expand Up @@ -9,9 +9,12 @@ declare(strict_types=1);
use Nette\Bridges\CacheLatte\CacheMacro;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';

if (version_compare(Latte\Engine::VERSION, '3', '>')) {
Tester\Environment::skip('Test for Latte 2');
}


$latte = new Latte\Engine;
$latte->setTempDirectory(getTempDir());
Expand Down
Expand Up @@ -11,9 +11,13 @@ use Nette\Caching\Cache;
use Nette\Caching\Storages\DevNullStorage;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';

if (version_compare(Latte\Engine::VERSION, '3', '>')) {
Tester\Environment::skip('Test for Latte 2');
}


test('', function () {
$parents = [];
$dp = [Cache::Tags => ['rum', 'cola']];
Expand Down
Expand Up @@ -5,8 +5,7 @@
echo LR\Filters::escapeHtmlText(($this->filters->lower)($title)) /* line %d% */;
echo "\n";
Nette\Bridges\CacheLatte\CacheMacro::endCache($this->global->cacheStack) /* line %d% */;
}
catch (\Throwable $ʟ_e) {
} catch (\Throwable $ʟ_e) {
Nette\Bridges\CacheLatte\CacheMacro::rollback($this->global->cacheStack);
throw $ʟ_e;
}
Expand Down
Expand Up @@ -13,8 +13,7 @@
$this->createTemplate('include.cache.latte', ['localvar' => 11] + $this->params, 'include')->renderToContentType('html') /* line %d% */;
echo "\n";
Nette\Bridges\CacheLatte\CacheMacro::endCache($this->global->cacheStack, [$id, 'tags' => 'mytag']) /* line %d% */;
}
catch (\Throwable $ʟ_e) {
} catch (\Throwable $ʟ_e) {
Nette\Bridges\CacheLatte\CacheMacro::rollback($this->global->cacheStack);
throw $ʟ_e;
}
Expand Down
File renamed without changes.
49 changes: 49 additions & 0 deletions tests/Bridges.Latte3/CacheNode.phpt
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

use Nette\Bridges\CacheLatte\Nodes\CacheNode;
use Nette\Caching\Cache;
use Nette\Caching\Storages\DevNullStorage;
use Tester\Assert;

require __DIR__ . '/../bootstrap.php';

if (version_compare(Latte\Engine::VERSION, '3', '<')) {
Tester\Environment::skip('Test for Latte 3');
}


test('', function () {
$parents = [];
$dp = [Cache::Tags => ['rum', 'cola']];
$outputHelper = CacheNode::createCache(new DevNullStorage, 'test', $parents, $dp);
Assert::type(Nette\Caching\OutputHelper::class, $outputHelper);
CacheNode::endCache($parents);
Assert::same($dp + [Cache::Expire => '+ 7 days'], $outputHelper->dependencies);
});

test('', function () {
$parents = [];
$dp = [Cache::Tags => ['rum', 'cola']];
$dpFallback = function () use ($dp) {
return $dp;
};
$outputHelper = CacheNode::createCache(new DevNullStorage, 'test', $parents, ['dependencies' => $dpFallback]);
CacheNode::endCache($parents);
Assert::same($dp + [Cache::Expire => '+ 7 days'], $outputHelper->dependencies);
});

test('', function () {
$parents = [];
$dp = [
Cache::Tags => ['rum', 'cola'],
Cache::Expire => '+ 1 days',
];
$dpFallback = function () use ($dp) {
return $dp;
};
$outputHelper = CacheNode::createCache(new DevNullStorage, 'test', $parents, ['dependencies' => $dpFallback]);
CacheNode::endCache($parents);
Assert::same($dp, $outputHelper->dependencies);
});
8 changes: 8 additions & 0 deletions tests/Bridges.Latte3/expected/cache.html
@@ -0,0 +1,8 @@
Noncached content


<h1>HELLO</h1>

<p>Included file (11)</p>

hello
14 changes: 14 additions & 0 deletions tests/Bridges.Latte3/expected/cache.inc.phtml
@@ -0,0 +1,14 @@
<?php
%A%
if (Nette\Bridges\CacheLatte\Nodes\CacheNode::createCache($this->global->cacheStorage, '%[\w]+%', $this->global->cacheStack)) /* line %d% */
try {
echo ' ';
echo LR\Filters::escapeHtmlText(($this->filters->lower)($title)) /* line %d% */;
echo "\n";

Nette\Bridges\CacheLatte\Nodes\CacheNode::endCache($this->global->cacheStack) /* line %d% */;
} catch (\Throwable $ʟ_e) {
Nette\Bridges\CacheLatte\Nodes\CacheNode::rollback($this->global->cacheStack);
throw $ʟ_e;
}
%A%

0 comments on commit 7a59a77

Please sign in to comment.