Skip to content

Commit

Permalink
Latte 3 support (#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinMystikJonas authored Jul 14, 2022
1 parent ed1d146 commit d24a581
Show file tree
Hide file tree
Showing 12 changed files with 411 additions and 27 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ jobs:
name: "Static analysis"
runs-on: "ubuntu-latest"

strategy:
matrix:
composer-args: [ "" ]
command: [ "phpstan" ]
include:
- composer-args: "--prefer-lowest"
command: "phpstan-lowest"
fail-fast: false

steps:
- name: "Checkout"
uses: "actions/checkout@v2"
Expand Down Expand Up @@ -115,10 +124,10 @@ jobs:
restore-keys: "${{ runner.os }}-composer-"

- name: "Install dependencies"
run: "${{ env.composer-install }}"
run: "${{ env.composer-install }} ${{ matrix.composer-args }}"

- name: "PHPStan"
run: "make phpstan"
run: "make ${{ matrix.command}}"

tests:
name: "Tests"
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ csf: vendor
phpstan: vendor
vendor/bin/phpstan analyse -l max -c phpstan.neon src

phpstan-lowest: vendor
vendor/bin/phpstan analyse -l max -c phpstan.lowest.neon src

tests: vendor
vendor/bin/tester -s -p php --colors 1 -C tests/Tests

Expand Down
9 changes: 6 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
],
"require": {
"php": "^8.0.2",
"latte/latte": "^2.6",
"latte/latte": "^2.6|^3.0",
"nette/di": "^3.0.6",
"nette/finder": "^2.5.2",
"nette/http": "^3.0",
Expand All @@ -37,7 +37,7 @@
"nette/tester": "^2.3.1",
"ninjify/nunjuck": "^0.3.0",
"ninjify/qa": "^0.13",
"phpstan/phpstan": "^1.4",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-nette": "^1.0",
"phpstan/phpstan-strict-rules": "^1.1",
Expand All @@ -55,7 +55,10 @@
}
},
"config": {
"sort-packages": true
"sort-packages": true,
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"extra": {
"branch-alias": {
Expand Down
71 changes: 71 additions & 0 deletions phpstan.lowest.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
includes:
- vendor/phpstan/phpstan-deprecation-rules/rules.neon
- vendor/phpstan/phpstan-nette/extension.neon
- vendor/phpstan/phpstan-nette/rules.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon

parameters:
level: max
paths:
- src
- tests
excludePaths:
- src/Latte/TranslatorExtension.php
- src/Latte/Nodes/*
ignoreErrors:
-
count: 2
message: '#^Variable property access on object\.$#'
path: 'src/Loaders/Doctrine.php'

# -------------------------------------------------------------------
# for back compatibility with old packages - will be remove in future
# -------------------------------------------------------------------

-
message: """
#^Fetching class constant class of deprecated class Nette\\\\Localization\\\\ITranslator\\:
use Nette\\\\Localization\\\\Translator$#
"""
count: 2
path: src/DI/TranslationExtension.php

-
count: 1
message: """
#^Parameter \\$translator of method Contributte\\\\Translation\\\\Latte\\\\Filters\\:\\:__construct\\(\\) has typehint with deprecated interface Nette\\\\Localization\\\\ITranslator\\:
use Nette\\\\Localization\\\\Translator$#
"""
path: src/Latte/Filters.php

-
count: 1
message: """
#^Call to an undefined method Nette\\\\Localization\\\\ITranslator::translate\\(\\)#
"""
path: src/Latte/Filters.php

-
count: 1
message: """
#^Parameter \\$translator of method Contributte\\\\Translation\\\\Latte\\\\TranslatorExtension\\:\\:__construct\\(\\) has typehint with deprecated interface Nette\\\\Localization\\\\ITranslator\\:
use Nette\\\\Localization\\\\Translator$#
"""
path: src/Latte/TranslatorExtension.php

-
count: 1
message: """
#^Class Contributte\\\\Translation\\\\PrefixedTranslator implements deprecated interface Nette\\\\Localization\\\\ITranslator\\:
use Nette\\\\Localization\\\\Translator$#
"""
path: src/PrefixedTranslator.php

-
count: 1
message: """
#^Class Contributte\\\\Translation\\\\Translator implements deprecated interface Nette\\\\Localization\\\\ITranslator\\:
use Nette\\\\Localization\\\\Translator$#
"""
path: src/Translator.php

11 changes: 11 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ parameters:
paths:
- src
- tests
excludePaths:
- src/Latte/Filters.php
- src/Latte/Macros.php
ignoreErrors:
-
count: 2
Expand Down Expand Up @@ -57,6 +60,14 @@ parameters:
"""
path: src/Latte/Filters.php

-
count: 1
message: """
#^Parameter \\$translator of method Contributte\\\\Translation\\\\Latte\\\\TranslatorExtension\\:\\:__construct\\(\\) has typehint with deprecated interface Nette\\\\Localization\\\\ITranslator\\:
use Nette\\\\Localization\\\\Translator$#
"""
path: src/Latte/TranslatorExtension.php

-
count: 1
message: """
Expand Down
17 changes: 13 additions & 4 deletions src/DI/TranslationExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Contributte\Translation\Helpers;
use Contributte\Translation\Latte\Filters;
use Contributte\Translation\Latte\Macros;
use Contributte\Translation\Latte\TranslatorExtension;
use Contributte\Translation\Loaders\Neon;
use Contributte\Translation\LocaleResolver;
use Contributte\Translation\LocalesResolvers\Header;
Expand Down Expand Up @@ -238,10 +239,18 @@ public function beforeCompile(): void
/** @var \Nette\DI\Definitions\FactoryDefinition $latteFactory */
$latteFactory = $builder->getDefinition($latteFactoryName);

$latteFactory->getResultDefinition()
->addSetup('?->onCompile[] = function (Latte\\Engine $engine): void { ?::install($engine->getCompiler()); }', ['@self', new PhpLiteral(Macros::class)])
->addSetup('addProvider', ['translator', $iTranslator])
->addSetup('addFilter', ['translate', [$latteFilters, 'translate']]);
/** @phpstan-ignore-next-line */
if (version_compare(\Latte\Engine::VERSION, '3', '<')) {
$latteFactory->getResultDefinition()
->addSetup('?->onCompile[] = function (Latte\\Engine $engine): void { ?::install($engine->getCompiler()); }', ['@self', new PhpLiteral(Macros::class)])
->addSetup('addProvider', ['translator', $iTranslator])
->addSetup('addFilter', ['translate', [$latteFilters, 'translate']]);
} else {
$latteExtension = $builder->addDefinition($this->prefix('latte.extension'))
->setFactory(TranslatorExtension::class);
$latteFactory->getResultDefinition()
->addSetup('addExtension', [$latteExtension]);
}
}

/** @var \Contributte\Translation\DI\TranslationProviderInterface $v1 */
Expand Down
29 changes: 18 additions & 11 deletions src/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Contributte\Translation;

use Latte\MacroNode;
use Nette\Utils\Strings;

class Helpers
Expand Down Expand Up @@ -38,27 +37,35 @@ public static function extractMessage(
return [$domain, $message];
}

public static function macroWithoutParameters(
MacroNode $node
): bool
{
$result = Strings::trim($node->tokenizer->joinUntil(',')) === Strings::trim($node->args);
$node->tokenizer->reset();
return $result;
}

public static function isAbsoluteMessage(
string $message
): bool
{
return Strings::startsWith($message, '//');
}

/**
* @param mixed $message
* @param array<string>|null $prefix
* @return mixed
*/
public static function prefixMessage(
$message,
?array $prefix
)
{
if (is_string($message) && $prefix !== null && !self::isAbsoluteMessage($message)) {
$message = implode('.', $prefix) . '.' . $message;
}

return $message;
}

public static function createLatteProperty(
string $suffix
): string
{
return '$ʟ_contributteTranslation' . $suffix;
return '$ᴛ_contributteTranslation' . $suffix;
}

}
14 changes: 13 additions & 1 deletion src/Latte/Macros.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Latte\MacroNode;
use Latte\Macros\MacroSet;
use Latte\PhpWriter;
use Nette\Utils\Strings;

class Macros extends MacroSet
{
Expand Down Expand Up @@ -50,8 +51,10 @@ public function macroTranslate(
$value = 'ob_get_clean()';
}

/** @phpstan-ignore-next-line */
if (!defined(Engine::class . '::VERSION_ID') || Engine::VERSION_ID < 20900) {
$latteProp = '$_fi';
/** @phpstan-ignore-next-line */
} elseif (Engine::VERSION_ID >= 20900 && Engine::VERSION_ID < 20902) {
$latteProp = '$__fi';
} else {
Expand All @@ -65,7 +68,7 @@ public function macroTranslate(
$messageProp = Helpers::createLatteProperty('Message');
$prefixProp = Helpers::createLatteProperty('Prefix');

$macroCodeEcho = Helpers::macroWithoutParameters($node)
$macroCodeEcho = self::macroWithoutParameters($node)
? sprintf('echo %%modify(call_user_func($this->filters->translate, %s))', $messageProp)
: sprintf('echo %%modify(call_user_func($this->filters->translate, %s, %%node.args))', $messageProp);

Expand Down Expand Up @@ -121,4 +124,13 @@ public function macroPrefix(
', $tempPrefixProp, $tempPrefixProp, $prefixProp, $tempPrefixProp, $prefixProp, $prefixProp));
}

public static function macroWithoutParameters(
MacroNode $node
): bool
{
$result = Strings::trim($node->tokenizer->joinUntil(',')) === Strings::trim($node->args);
$node->tokenizer->reset();
return $result;
}

}
91 changes: 91 additions & 0 deletions src/Latte/Nodes/TranslateNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php declare(strict_types = 1);

namespace Contributte\Translation\Latte\Nodes;

use Latte\Compiler\NodeHelpers;
use Latte\Compiler\Nodes\AreaNode;
use Latte\Compiler\Nodes\NopNode;
use Latte\Compiler\Nodes\Php;
use Latte\Compiler\Nodes\Php\ModifierNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\Nodes\TextNode;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;

class TranslateNode extends StatementNode
{

public AreaNode $content;

public ModifierNode $modifier;

/** @return \Generator<int, ?array<mixed>, array{AreaNode, ?Tag}, TranslateNode|NopNode> */
public static function create(
Tag $tag
): \Generator
{
$tag->outputMode = $tag::OutputKeepIndentation;

$node = new TranslateNode();
$args = $tag->parser->parseArguments();
$node->modifier = $tag->parser->parseModifier();
$node->modifier->escape = true;
if ($tag->void) {
return new NopNode();
}

[$node->content] = yield;

if (($text = NodeHelpers::toText($node->content)) !== null) {
$node->content = new TextNode($text);
}

array_unshift($node->modifier->filters, new Php\FilterNode(new Php\IdentifierNode('translate'), $args->toArguments()));

return $node;
}


public function print(
PrintContext $context
): string
{
if ($this->content instanceof TextNode) {
return $context->format(
'
$ʟ_fi = new LR\FilterInfo(%dump);
echo %modifyContent(%dump) %line;
',
$context->getEscaper()->export(),
$this->modifier,
$this->content->content,
$this->position,
);

} else {
return $context->format(
'
ob_start(fn() => ""); try {
%node
} finally {
$ʟ_tmp = ob_get_clean();
}
$ʟ_fi = new LR\FilterInfo(%dump);
echo %modifyContent($ʟ_tmp) %line;
',
$this->content,
$context->getEscaper()->export(),
$this->modifier,
$this->position,
);
}
}


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

}
Loading

0 comments on commit d24a581

Please sign in to comment.