From 859151ea0491345d2d58239920129a4901255781 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 14 Dec 2023 22:21:35 +0100 Subject: [PATCH 01/21] opened 4.0-dev --- composer.json | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index d0622ade4..968691395 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,7 @@ }, "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "4.0-dev" } } } diff --git a/readme.md b/readme.md index d8e52ef86..b4b61840e 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ Nette Application MVC ===================== [![Downloads this Month](https://img.shields.io/packagist/dm/nette/application.svg)](https://packagist.org/packages/nette/application) -[![Tests](https://github.com/nette/application/actions/workflows/tests.yml/badge.svg?branch=v3.2)](https://github.com/nette/application/actions) +[![Tests](https://github.com/nette/application/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/nette/application/actions) [![Latest Stable Version](https://poser.pugx.org/nette/application/v/stable)](https://github.com/nette/application/releases) [![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/application/blob/master/license.md) From b3ad622e359d2f5a1bc42e0194c0929c0a4ba318 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sat, 6 Apr 2024 18:50:00 +0200 Subject: [PATCH 02/21] removed support for Latte 2 --- composer.json | 4 +- src/Bridges/ApplicationDI/LatteExtension.php | 65 ++---- .../ApplicationLatte/SnippetBridge.php | 95 --------- src/Bridges/ApplicationLatte/Template.php | 11 +- .../ApplicationLatte/TemplateFactory.php | 57 +----- src/Bridges/ApplicationLatte/UIMacros.php | 187 ------------------ src/Bridges/ApplicationLatte/UIRuntime.php | 84 -------- tests/Bridges.DI/LatteExtension.2.phpt | 122 ------------ tests/Bridges.DI/LatteExtension.basic.phpt | 4 - .../Template.getParentName().phpt | 58 ------ .../TemplateFactory.customTemplate.phpt | 75 ------- .../TemplateFactory.filters.phpt | 47 ----- .../TemplateFactory.nonce.control.phpt | 39 ---- .../TemplateFactory.nonce.presenter.phpt | 42 ---- .../TemplateFactory.onCompile.phpt | 80 -------- .../TemplateFactory.onCreate.phpt | 36 ---- tests/Bridges.Latte2/UIMacros.control.2.phpt | 86 -------- tests/Bridges.Latte2/UIMacros.control.3.phpt | 51 ----- tests/Bridges.Latte2/UIMacros.control.phpt | 88 --------- .../UIMacros.isLinkCurrent.phpt | 54 ----- tests/Bridges.Latte2/UIMacros.link.2.phpt | 122 ------------ tests/Bridges.Latte2/UIMacros.link.phpt | 68 ------- .../UIMacros.renderSnippets.phpt | 97 --------- .../UIMacros.renderSnippets2.phpt | 84 -------- .../UIMacros.renderSnippets3.phpt | 73 ------- .../UIMacros.renderSnippets4.phpt | 54 ----- .../UIMacros.renderSnippets5.phpt | 59 ------ .../UIMacros.renderSnippets6.phpt | 45 ----- .../expected/UIMacros.isLinkCurrent.php | 22 --- .../expected/UIMacros.renderSnippets.html | 20 -- tests/Bridges.Latte2/templates/include3.latte | 1 - .../templates/snippet-include.latte | 25 --- .../templates/snippet-included.latte | 1 - .../Template.getParentName().phpt | 4 - .../TemplateFactory.customTemplate.phpt | 4 - .../TemplateFactory.onCreate.phpt | 4 - tests/Bridges.Latte3/UIExtension.filters.phpt | 4 - .../UIExtension.nonce.control.phpt | 4 - .../UIExtension.nonce.presenter.phpt | 4 - tests/Bridges.Latte3/isLinkCurrent().phpt | 4 - tests/Bridges.Latte3/n-snippet.2.phpt | 4 - tests/Bridges.Latte3/n-snippet.block.phpt | 4 - tests/Bridges.Latte3/n-snippet.dynamic.phpt | 4 - tests/Bridges.Latte3/n-snippet.phpt | 3 - tests/Bridges.Latte3/renderSnippets.phpt | 4 - tests/Bridges.Latte3/renderSnippets2.phpt | 4 - tests/Bridges.Latte3/renderSnippets3.phpt | 4 - tests/Bridges.Latte3/renderSnippets4.phpt | 4 - tests/Bridges.Latte3/renderSnippets5.phpt | 4 - tests/Bridges.Latte3/renderSnippets6.phpt | 4 - tests/Bridges.Latte3/renderSnippets7.phpt | 4 - tests/Bridges.Latte3/{control}.2.phpt | 4 - tests/Bridges.Latte3/{control}.3.phpt | 3 - tests/Bridges.Latte3/{control}.phpt | 4 - tests/Bridges.Latte3/{ifCurrent}.phpt | 4 - tests/Bridges.Latte3/{link}.2.phpt | 4 - tests/Bridges.Latte3/{link}.phpt | 4 - tests/Bridges.Latte3/{snippet}.dynamic.phpt | 4 - tests/Bridges.Latte3/{snippet}.phpt | 4 - 59 files changed, 17 insertions(+), 2041 deletions(-) delete mode 100644 src/Bridges/ApplicationLatte/SnippetBridge.php delete mode 100644 src/Bridges/ApplicationLatte/UIMacros.php delete mode 100644 src/Bridges/ApplicationLatte/UIRuntime.php delete mode 100644 tests/Bridges.DI/LatteExtension.2.phpt delete mode 100644 tests/Bridges.Latte2/Template.getParentName().phpt delete mode 100644 tests/Bridges.Latte2/TemplateFactory.customTemplate.phpt delete mode 100644 tests/Bridges.Latte2/TemplateFactory.filters.phpt delete mode 100644 tests/Bridges.Latte2/TemplateFactory.nonce.control.phpt delete mode 100644 tests/Bridges.Latte2/TemplateFactory.nonce.presenter.phpt delete mode 100644 tests/Bridges.Latte2/TemplateFactory.onCompile.phpt delete mode 100644 tests/Bridges.Latte2/TemplateFactory.onCreate.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.control.2.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.control.3.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.control.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.isLinkCurrent.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.link.2.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.link.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.renderSnippets.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.renderSnippets2.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.renderSnippets3.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.renderSnippets4.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.renderSnippets5.phpt delete mode 100644 tests/Bridges.Latte2/UIMacros.renderSnippets6.phpt delete mode 100644 tests/Bridges.Latte2/expected/UIMacros.isLinkCurrent.php delete mode 100644 tests/Bridges.Latte2/expected/UIMacros.renderSnippets.html delete mode 100644 tests/Bridges.Latte2/templates/include3.latte delete mode 100644 tests/Bridges.Latte2/templates/snippet-include.latte delete mode 100644 tests/Bridges.Latte2/templates/snippet-included.latte diff --git a/composer.json b/composer.json index 968691395..12c227b6f 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "nette/forms": "^3.2", "nette/robot-loader": "^4.0", "nette/security": "^3.2", - "latte/latte": "^2.10.2 || ^3.0.12", + "latte/latte": "^3.0.12", "tracy/tracy": "^2.9", "mockery/mockery": "^2.0", "phpstan/phpstan-nette": "^1.0", @@ -42,7 +42,7 @@ "nette/di": "<3.2", "nette/forms": "<3.2", "nette/schema": "<1.3", - "latte/latte": "<2.7.1 || >=3.0.0 <3.0.12 || >=3.1", + "latte/latte": "<3.0.12", "tracy/tracy": "<2.9" }, "autoload": { diff --git a/src/Bridges/ApplicationDI/LatteExtension.php b/src/Bridges/ApplicationDI/LatteExtension.php index cbe5093a7..5a9cb0858 100644 --- a/src/Bridges/ApplicationDI/LatteExtension.php +++ b/src/Bridges/ApplicationDI/LatteExtension.php @@ -33,7 +33,6 @@ public function getConfigSchema(): Nette\Schema\Schema { return Expect::structure([ 'debugger' => Expect::anyOf(true, false, 'all'), - 'macros' => Expect::arrayOf('string'), 'extensions' => Expect::arrayOf('string|Nette\DI\Definitions\Statement'), 'templateClass' => Expect::string(), 'strictTypes' => Expect::bool(false), @@ -52,36 +51,26 @@ public function loadConfiguration(): void $config = $this->config; $builder = $this->getContainerBuilder(); - $latteFactory = $builder->addFactoryDefinition($this->prefix('latteFactory')) + $builder->addFactoryDefinition($this->prefix('latteFactory')) ->setImplement(ApplicationLatte\LatteFactory::class) ->getResultDefinition() ->setFactory(Latte\Engine::class) ->addSetup('setTempDirectory', [$this->tempDir]) ->addSetup('setAutoRefresh', [$this->debugMode]) - ->addSetup('setStrictTypes', [$config->strictTypes]); - - if (version_compare(Latte\Engine::VERSION, '3', '<')) { - foreach ($config->macros as $macro) { - $this->addMacro($macro); - } - } else { - $latteFactory->addSetup('setStrictParsing', [$config->strictParsing]) - ->addSetup('enablePhpLinter', [$config->phpLinter]); - - $builder->getDefinition($this->prefix('latteFactory')) - ->getResultDefinition() + ->addSetup('setStrictTypes', [$config->strictTypes]) + ->addSetup('setStrictParsing', [$config->strictParsing]) + ->addSetup('enablePhpLinter', [$config->phpLinter]) ->addSetup('?', [$builder::literal('func_num_args() && $service->addExtension(new Nette\Bridges\ApplicationLatte\UIExtension(func_get_arg(0)))')]); - if ($builder->getByType(Nette\Caching\Storage::class)) { - $this->addExtension(new Statement(Nette\Bridges\CacheLatte\CacheExtension::class)); - } - if (class_exists(Nette\Bridges\FormsLatte\FormsExtension::class)) { - $this->addExtension(new Statement(Nette\Bridges\FormsLatte\FormsExtension::class)); - } + if ($builder->getByType(Nette\Caching\Storage::class)) { + $this->addExtension(new Statement(Nette\Bridges\CacheLatte\CacheExtension::class)); + } + if (class_exists(Nette\Bridges\FormsLatte\FormsExtension::class)) { + $this->addExtension(new Statement(Nette\Bridges\FormsLatte\FormsExtension::class)); + } - foreach ($config->extensions as $extension) { - $this->addExtension($extension); - } + foreach ($config->extensions as $extension) { + $this->addExtension($extension); } $builder->addDefinition($this->prefix('templateFactory')) @@ -124,40 +113,12 @@ public static function initLattePanel( $control = $template->getLatte()->getProviders()['uiControl'] ?? null; if ($all || $control instanceof Nette\Application\UI\Presenter) { $name = $all && $control ? (new \ReflectionObject($control))->getShortName() : ''; - if (version_compare(Latte\Engine::VERSION, '3', '<')) { - $bar->addPanel(new Latte\Bridges\Tracy\LattePanel($template->getLatte(), $name)); - } else { - $template->getLatte()->addExtension(new Latte\Bridges\Tracy\TracyExtension($name)); - } + $template->getLatte()->addExtension(new Latte\Bridges\Tracy\TracyExtension($name)); } }; } - public function addMacro(string $macro): void - { - $builder = $this->getContainerBuilder(); - $definition = $builder->getDefinition($this->prefix('latteFactory'))->getResultDefinition(); - - if (($macro[0] ?? null) === '@') { - if (str_contains($macro, '::')) { - [$macro, $method] = explode('::', $macro); - } else { - $method = 'install'; - } - - $definition->addSetup('?->onCompile[] = function ($engine) { ?->' . $method . '($engine->getCompiler()); }', ['@self', $macro]); - - } else { - if (!str_contains($macro, '::') && class_exists($macro)) { - $macro .= '::install'; - } - - $definition->addSetup('?->onCompile[] = function ($engine) { ' . $macro . '($engine->getCompiler()); }', ['@self']); - } - } - - public function addExtension(Statement|string $extension): void { $extension = is_string($extension) diff --git a/src/Bridges/ApplicationLatte/SnippetBridge.php b/src/Bridges/ApplicationLatte/SnippetBridge.php deleted file mode 100644 index f5d62ef80..000000000 --- a/src/Bridges/ApplicationLatte/SnippetBridge.php +++ /dev/null @@ -1,95 +0,0 @@ -control = $control; - } - - - public function isSnippetMode(): bool - { - return (bool) $this->control->snippetMode; - } - - - public function setSnippetMode($snippetMode) - { - $this->control->snippetMode = $snippetMode; - } - - - public function needsRedraw($name): bool - { - return $this->control->isControlInvalid($name); - } - - - public function markRedrawn($name): void - { - if ($name !== '') { - $this->control->redrawControl($name, false); - } - } - - - public function getHtmlId($name): string - { - return $this->control->getSnippetId($name); - } - - - public function addSnippet($name, $content): void - { - if (!isset($this->payload)) { - $this->payload = $this->control->getPresenter()->getPayload(); - } - - $this->payload->snippets[$this->control->getSnippetId($name)] = $content; - } - - - public function renderChildren(): void - { - $queue = [$this->control]; - do { - foreach (array_shift($queue)->getComponents() as $child) { - if ($child instanceof Renderable) { - if ($child->isControlInvalid()) { - $child->snippetMode = true; - $child->render(); - $child->snippetMode = false; - } - } elseif ($child instanceof Nette\ComponentModel\IContainer) { - $queue[] = $child; - } - } - } while ($queue); - } -} diff --git a/src/Bridges/ApplicationLatte/Template.php b/src/Bridges/ApplicationLatte/Template.php index c07ea9975..335e14440 100644 --- a/src/Bridges/ApplicationLatte/Template.php +++ b/src/Bridges/ApplicationLatte/Template.php @@ -94,16 +94,7 @@ public function addFunction(string $name, callable $callback): static */ public function setTranslator(?Nette\Localization\Translator $translator, ?string $language = null): static { - if (version_compare(Latte\Engine::VERSION, '3', '<')) { - $this->latte->addFilter( - 'translate', - fn(Latte\Runtime\FilterInfo $fi, ...$args): string => $translator === null - ? $args[0] - : $translator->translate(...$args), - ); - } else { - $this->latte->addExtension(new Latte\Essential\TranslatorExtension($translator, $language)); - } + $this->latte->addExtension(new Latte\Essential\TranslatorExtension($translator, $language)); return $this; } diff --git a/src/Bridges/ApplicationLatte/TemplateFactory.php b/src/Bridges/ApplicationLatte/TemplateFactory.php index 2fdcbc9b4..5ae96343d 100644 --- a/src/Bridges/ApplicationLatte/TemplateFactory.php +++ b/src/Bridges/ApplicationLatte/TemplateFactory.php @@ -9,7 +9,6 @@ namespace Nette\Bridges\ApplicationLatte; -use Latte; use Nette; use Nette\Application\UI; @@ -28,7 +27,6 @@ public function __construct( private readonly LatteFactory $latteFactory, private readonly ?Nette\Http\IRequest $httpRequest = null, private readonly ?Nette\Security\User $user = null, - private readonly ?Nette\Caching\Storage $cacheStorage = null, $templateClass = null, ) { if ($templateClass && (!class_exists($templateClass) || !is_a($templateClass, Template::class, true))) { @@ -51,9 +49,7 @@ public function createTemplate(?UI\Control $control = null, ?string $class = nul $template = new $class($latte); $presenter = $control?->getPresenterIfExists(); - if (version_compare(Latte\Engine::VERSION, '3', '<')) { - $this->setupLatte2($latte, $control, $presenter, $template); - } elseif (!Nette\Utils\Arrays::some($latte->getExtensions(), fn($e) => $e instanceof UIExtension)) { + if (!Nette\Utils\Arrays::some($latte->getExtensions(), fn($e) => $e instanceof UIExtension)) { $latte->addExtension(new UIExtension($control)); } @@ -84,55 +80,4 @@ public function createTemplate(?UI\Control $control = null, ?string $class = nul return $template; } - - - private function setupLatte2( - Latte\Engine $latte, - ?UI\Control $control, - ?UI\Presenter $presenter, - Template $template, - ): void - { - if ($latte->onCompile instanceof \Traversable) { - $latte->onCompile = iterator_to_array($latte->onCompile); - } - - array_unshift($latte->onCompile, function (Latte\Engine $latte) use ($control, $template): void { - if ($this->cacheStorage) { - $latte->getCompiler()->addMacro('cache', new Nette\Bridges\CacheLatte\CacheMacro); - } - - UIMacros::install($latte->getCompiler()); - if (class_exists(Nette\Bridges\FormsLatte\FormMacros::class)) { - Nette\Bridges\FormsLatte\FormMacros::install($latte->getCompiler()); - } - - $control?->templatePrepareFilters($template); - }); - - $latte->addProvider('cacheStorage', $this->cacheStorage); - - if ($control) { - $latte->addProvider('uiControl', $control); - $latte->addProvider('uiPresenter', $presenter); - $latte->addProvider('snippetBridge', new SnippetBridge($control)); - if ($presenter) { - $header = $presenter->getHttpResponse()->getHeader('Content-Security-Policy') - ?: $presenter->getHttpResponse()->getHeader('Content-Security-Policy-Report-Only'); - } - - $nonce = $presenter && preg_match('#\s\'nonce-([\w+/]+=*)\'#', (string) $header, $m) ? $m[1] : null; - $latte->addProvider('uiNonce', $nonce); - } - - if ($presenter) { - $latte->addFunction('isLinkCurrent', [$presenter, 'isLinkCurrent']); - $latte->addFunction('isModuleCurrent', [$presenter, 'isModuleCurrent']); - } - - $latte->addFilter('modifyDate', fn($time, $delta, $unit = null) => $time - ? Nette\Utils\DateTime::from($time)->modify($delta . $unit) - : null); - - } } diff --git a/src/Bridges/ApplicationLatte/UIMacros.php b/src/Bridges/ApplicationLatte/UIMacros.php deleted file mode 100644 index 131c30075..000000000 --- a/src/Bridges/ApplicationLatte/UIMacros.php +++ /dev/null @@ -1,187 +0,0 @@ -addMacro('control', [$me, 'macroControl']); - - $me->addMacro('href', null, null, fn(MacroNode $node, PhpWriter $writer): string => ' ?> href="macroLink($node, $writer) . ' ?>"addMacro('plink', [$me, 'macroLink']); - $me->addMacro('link', [$me, 'macroLink']); - $me->addMacro('ifCurrent', [$me, 'macroIfCurrent'], '}'); // deprecated; use n:class="$presenter->linkCurrent ? ..." - $me->addMacro('extends', [$me, 'macroExtends']); - $me->addMacro('layout', [$me, 'macroExtends']); - $me->addMacro('nonce', null, null, 'echo $this->global->uiNonce ? " nonce=\"{$this->global->uiNonce}\"" : "";'); - $me->addMacro('templatePrint', [$me, 'macroTemplatePrint'], null, null, self::ALLOWED_IN_HEAD); - } - - - /** - * Initializes before template parsing. - */ - public function initialize(): void - { - $this->extends = false; - } - - - /** - * Finishes template parsing. - * @return array(prolog, epilog) - */ - public function finalize() - { - if ($this->printTemplate) { - return ["Nette\\Bridges\\ApplicationLatte\\UIRuntime::printClass(\$this, $this->printTemplate); exit;"]; - } - - return [$this->extends . 'Nette\Bridges\ApplicationLatte\UIRuntime::initialize($this, $this->parentName, $this->blocks);']; - } - - - /********************* macros ****************d*g**/ - - - /** - * {control name[:method] [params]} - */ - public function macroControl(MacroNode $node, PhpWriter $writer) - { - if ($node->context !== [Latte\Compiler::CONTENT_HTML, Latte\Compiler::CONTEXT_HTML_TEXT]) { - $escapeMod = Latte\Helpers::removeFilter($node->modifiers, 'noescape') ? '' : '|escape'; - } - - if ($node->modifiers) { - trigger_error('Modifiers are deprecated in ' . $node->getNotation(), E_USER_DEPRECATED); - } - - $node->modifiers .= $escapeMod ?? ''; - - $words = $node->tokenizer->fetchWords(); - if (!$words) { - throw new CompileException('Missing control name in {control}'); - } - - $name = $writer->formatWord($words[0]); - $method = ucfirst($words[1] ?? ''); - $method = Strings::match($method, '#^\w*$#D') - ? "render$method" - : "{\"render$method\"}"; - - $tokens = $node->tokenizer; - $pos = $tokens->position; - $wrap = false; - while ($tokens->nextToken()) { - if ($tokens->isCurrent('=>', '(expand)') && !$tokens->depth) { - $wrap = true; - break; - } - } - - $tokens->position = $pos; - $param = $wrap ? $writer->formatArray() : $writer->formatArgs(); - - return "/* line $node->startLine */ " - . ($name[0] === '$' ? "if (is_object($name)) \$_tmp = $name; else " : '') - . '$_tmp = $this->global->uiControl->getComponent(' . $name . '); ' - . 'if ($_tmp instanceof Nette\Application\UI\Renderable) $_tmp->redrawControl(null, false); ' - . ($node->modifiers === '' - ? "\$_tmp->$method($param);" - : $writer->write( - "ob_start(fn() => null); \$_tmp->$method($param); \$ʟ_fi = new LR\\FilterInfo(%var); echo %modifyContent(ob_get_clean());", - Latte\Engine::CONTENT_HTML, - ) - ); - } - - - /** - * {link destination [,] [params]} - * {plink destination [,] [params]} - * n:href="destination [,] [params]" - */ - public function macroLink(MacroNode $node, PhpWriter $writer) - { - $node->modifiers = preg_replace('#\|safeurl\s*(?=\||$)#Di', '', $node->modifiers); - return $writer->using($node, $this->getCompiler()) - ->write( - 'echo %escape(%modify(' - . ($node->name === 'plink' ? '$this->global->uiPresenter' : '$this->global->uiControl') - . '->link(%node.word, %node.array?)))' - . ($node->startLine ? " /* line $node->startLine */;" : ';'), - ); - } - - - /** - * {ifCurrent destination [,] [params]} - */ - public function macroIfCurrent(MacroNode $node, PhpWriter $writer) - { - if ($node->modifiers) { - throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); - } - - return $writer->write( - $node->args - ? 'if ($this->global->uiPresenter->isLinkCurrent(%node.word, %node.array?)) {' - : 'if ($this->global->uiPresenter->getLastCreatedRequestFlag("current")) {', - ); - } - - - /** - * {extends auto} - */ - public function macroExtends(MacroNode $node, PhpWriter $writer) - { - if ($node->modifiers || $node->parentNode || $node->args !== 'auto') { - return $this->extends = false; - } - - $this->extends = $writer->write('$this->parentName = $this->global->uiPresenter->findLayoutTemplateFile();'); - } - - - /** - * {templatePrint [parentClass | default]} - */ - public function macroTemplatePrint(MacroNode $node): void - { - if ($node->modifiers) { - throw new CompileException('Modifiers are not allowed in ' . $node->getNotation()); - } - - $this->printTemplate = var_export($node->tokenizer->fetchWord() ?: null, true); - } -} diff --git a/src/Bridges/ApplicationLatte/UIRuntime.php b/src/Bridges/ApplicationLatte/UIRuntime.php deleted file mode 100644 index ace3af72d..000000000 --- a/src/Bridges/ApplicationLatte/UIRuntime.php +++ /dev/null @@ -1,84 +0,0 @@ -global; - $blocks = array_filter(array_keys($blocks), fn(string $s): bool => $s[0] !== '_'); - if ( - $parentName === null - && $blocks - && !$template->getReferringTemplate() - && ($providers->uiControl ?? null) instanceof Nette\Application\UI\Presenter - ) { - $parentName = $providers->uiControl->findLayoutTemplateFile(); - } - } - - - public static function printClass(Latte\Runtime\Template $template, ?string $parent = null): void - { - $blueprint = new Latte\Runtime\Blueprint; - $name = 'Template'; - $params = $template->getParameters(); - $control = $params['control'] ?? $params['presenter'] ?? null; - if ($control) { - $name = preg_replace('#(Control|Presenter)$#', '', $control::class) . 'Template'; - unset($params[$control instanceof Presenter ? 'control' : 'presenter']); - } - - if ($parent) { - if (!class_exists($parent)) { - $blueprint->printHeader("{templatePrint}: Class '$parent' doesn't exist."); - return; - } - - $params = array_diff_key($params, get_class_vars($parent)); - } - - $funcs = array_diff_key((array) $template->global->fn, (new Latte\Runtime\Defaults)->getFunctions()); - unset($funcs['isLinkCurrent'], $funcs['isModuleCurrent']); - - $namespace = new Php\PhpNamespace(Php\Helpers::extractNamespace($name)); - $class = $namespace->addClass(Php\Helpers::extractShortName($name)); - $class->setExtends($parent ?: Template::class); - if (!$parent) { - $class->addTrait(Nette\SmartObject::class); - } - - $blueprint->addProperties($class, $params, true); - $blueprint->addFunctions($class, $funcs); - - $end = $blueprint->printCanvas(); - $blueprint->printHeader('Native types'); - $blueprint->printCode((string) $namespace); - - $blueprint->addProperties($class, $params, false); - - $blueprint->printHeader('phpDoc types'); - $blueprint->printCode((string) $namespace); - echo $end; - } -} diff --git a/tests/Bridges.DI/LatteExtension.2.phpt b/tests/Bridges.DI/LatteExtension.2.phpt deleted file mode 100644 index 8144950b6..000000000 --- a/tests/Bridges.DI/LatteExtension.2.phpt +++ /dev/null @@ -1,122 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -class LoremIpsumMacros extends Latte\Macros\MacroSet -{ - public static function install(Latte\Compiler $compiler) - { - $me = new static($compiler); - $me->addMacro('lorem', 'lorem'); - Notes::add($me::class); - } -} - - -class IpsumLoremMacros extends Latte\Macros\MacroSet -{ - public static function install(Latte\Compiler $compiler) - { - $me = new static($compiler); - $me->addMacro('ipsum', 'ipsum'); - Notes::add($me::class); - } -} - - -class FooMacros extends Latte\Macros\MacroSet -{ - public static function install(Latte\Compiler $compiler) - { - $me = new static($compiler); - $me->addMacro('foo', 'foo'); - Notes::add($me::class); - } -} - - -class NonStaticMacrosFactory -{ - private string $parameter; - - - public function __construct($parameter) - { - $this->parameter = $parameter; - } - - - public function install(Latte\Compiler $compiler) - { - $macros = new Latte\Macros\MacroSet($compiler); - $macros->addMacro('foo', 'foo ' . $this->parameter); - Notes::add(static::class . '::install'); - } - - - public function create(Latte\Compiler $compiler) - { - $macros = new Latte\Macros\MacroSet($compiler); - $macros->addMacro('foo2', 'foo ' . $this->parameter); - Notes::add(static::class . '::create'); - } -} - - -class AnotherExtension extends Nette\DI\CompilerExtension -{ - public function beforeCompile() - { - foreach ($this->compiler->getExtensions(Nette\Bridges\ApplicationDI\LatteExtension::class) as $extension) { - $extension->addMacro('FooMacros::install'); - } - } -} - - -$loader = new DI\Config\Loader; -$config = $loader->load(Tester\FileMock::create(' -latte: - macros: - - LoremIpsumMacros - - IpsumLoremMacros::install - - @macroFactory - - @macroFactory::create - -services: - macroFactory: NonStaticMacrosFactory(foo) -', 'neon')); - -$compiler = new DI\Compiler; -$compiler->addExtension('latte', new Nette\Bridges\ApplicationDI\LatteExtension('', false)); -$compiler->addExtension('another', new AnotherExtension); -$code = $compiler->addConfig($config)->compile(); -eval($code); - -$container = new Container; - - -Assert::type(Nette\Bridges\ApplicationLatte\LatteFactory::class, $container->getService('nette.latteFactory')); -$container->getService('nette.latteFactory')->create()->setLoader(new Latte\Loaders\StringLoader)->compile(''); - -Assert::same([ - 'LoremIpsumMacros', - 'IpsumLoremMacros', - 'NonStaticMacrosFactory::install', - 'NonStaticMacrosFactory::create', - 'FooMacros', -], Notes::fetch()); diff --git a/tests/Bridges.DI/LatteExtension.basic.phpt b/tests/Bridges.DI/LatteExtension.basic.phpt index 09dc0d292..34ea641d5 100644 --- a/tests/Bridges.DI/LatteExtension.basic.phpt +++ b/tests/Bridges.DI/LatteExtension.basic.phpt @@ -11,10 +11,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - class MyExtension extends Latte\Extension { diff --git a/tests/Bridges.Latte2/Template.getParentName().phpt b/tests/Bridges.Latte2/Template.getParentName().phpt deleted file mode 100644 index 1253c4a4e..000000000 --- a/tests/Bridges.Latte2/Template.getParentName().phpt +++ /dev/null @@ -1,58 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -$presenter = Mockery::mock(Nette\Application\UI\Presenter::class) - ->shouldReceive('findLayoutTemplateFile')->andReturn('layout.latte') - ->mock(); - -$latte = new Latte\Engine; -$latte->setLoader(new Latte\Loaders\StringLoader); -$latte->addProvider('uiControl', $presenter); -UIMacros::install($latte->getCompiler()); - -$template = $latte->createTemplate(''); -$template->prepare(); -Assert::null($template->getParentName()); - -$template = $latte->createTemplate('{block}...{/block}'); -$template->prepare(); -Assert::null($template->getParentName()); - -$template = $latte->createTemplate('{block name}...{/block}'); -$template->prepare(); -Assert::same('layout.latte', $template->getParentName()); - -$template = $latte->createTemplate('{extends "file.latte"} {block name}...{/block}'); -$template->prepare(); -Assert::same('file.latte', $template->getParentName()); - -$template = $latte->createTemplate('{extends "file.latte"}'); -$template->prepare(); -Assert::same('file.latte', $template->getParentName()); - -$template = $latte->createTemplate( - '{extends $file} {block name}...{/block}', - ['file' => 'file.latte'], -); -$template->prepare(); -Assert::same('file.latte', $template->getParentName()); - -$template = $latte->createTemplate('{extends none}'); -$template->prepare(); -Assert::null($template->getParentName()); - -$latte->addProvider('uiPresenter', $presenter); -$template = $latte->createTemplate('{extends auto}'); -$template->prepare(); -Assert::same('layout.latte', $template->getParentName()); diff --git a/tests/Bridges.Latte2/TemplateFactory.customTemplate.phpt b/tests/Bridges.Latte2/TemplateFactory.customTemplate.phpt deleted file mode 100644 index 011d5b52f..000000000 --- a/tests/Bridges.Latte2/TemplateFactory.customTemplate.phpt +++ /dev/null @@ -1,75 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - -Tester\Environment::bypassFinals(); - - -class TemplateMock extends Template -{ - private $file = 'ko'; - - - public function render(?string $file = null, array $params = []): void - { - echo strrev($this->file); - } - - - public function setFile(string $file): static - { - $this->file = $file; - return $this; - } - - - public function getFile(): string - { - return $this->file; - } -} - - -test('', function () { - $latteFactory = Mockery::mock(LatteFactory::class); - $latteFactory->shouldReceive('create')->andReturn(new Latte\Engine); - $factory = new TemplateFactory($latteFactory); - Assert::type(Template::class, $factory->createTemplate()); -}); - -Assert::exception(function () { - $factory = new TemplateFactory(Mockery::mock(LatteFactory::class), null, null, null, stdClass::class); -}, Nette\InvalidArgumentException::class, 'Class stdClass does not implement Nette\Bridges\ApplicationLatte\Template or it does not exist.'); - - -test('', function () { - $latteFactory = Mockery::mock(LatteFactory::class); - $latteFactory->shouldReceive('create')->andReturn(new Latte\Engine); - $factory = new TemplateFactory($latteFactory, null, null, null, TemplateMock::class); - $template = $factory->createTemplate(); - Assert::type(TemplateMock::class, $template); - Assert::type(UI\Template::class, $template); - ob_start(); - $template->render(); - Assert::same('ok', ob_get_clean()); - $template->setFile('bla'); - ob_start(); - $template->render(); - Assert::same('alb', ob_get_clean()); -}); diff --git a/tests/Bridges.Latte2/TemplateFactory.filters.phpt b/tests/Bridges.Latte2/TemplateFactory.filters.phpt deleted file mode 100644 index 57e879543..000000000 --- a/tests/Bridges.Latte2/TemplateFactory.filters.phpt +++ /dev/null @@ -1,47 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -class LatteFactory implements Nette\Bridges\ApplicationLatte\LatteFactory -{ - private $engine; - - - public function __construct(Latte\Engine $engine) - { - $this->engine = $engine; - } - - - public function create(): Latte\Engine - { - return $this->engine; - } -} - -$factory = new TemplateFactory(new LatteFactory(new Latte\Engine)); -$latte = $factory->createTemplate()->getLatte(); - - -setlocale(LC_TIME, 'C'); -date_default_timezone_set('Europe/Prague'); - -Assert::null($latte->invokeFilter('modifyDate', [null, null])); -Assert::same('1978-01-24 11:40:00', (string) $latte->invokeFilter('modifyDate', [254_400_000, '+1 day'])); -Assert::same('1978-05-06 00:00:00', (string) $latte->invokeFilter('modifyDate', ['1978-05-05', '+1 day'])); -Assert::same('1978-05-06 00:00:00', (string) $latte->invokeFilter('modifyDate', [new DateTime('1978-05-05'), '1day'])); -Assert::same('1978-01-22 11:40:00', (string) $latte->invokeFilter('modifyDate', [254_400_000, -1, 'day'])); diff --git a/tests/Bridges.Latte2/TemplateFactory.nonce.control.phpt b/tests/Bridges.Latte2/TemplateFactory.nonce.control.phpt deleted file mode 100644 index 850629b36..000000000 --- a/tests/Bridges.Latte2/TemplateFactory.nonce.control.phpt +++ /dev/null @@ -1,39 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - -$latte = new Latte\Engine; - -$latteFactory = Mockery::mock(ApplicationLatte\LatteFactory::class); -$latteFactory->shouldReceive('create')->andReturn($latte); - -$response = Mockery::mock(Nette\Http\IResponse::class); -$response->shouldReceive('getHeader')->with('Content-Security-Policy')->andReturn("hello 'nonce-abcd123==' world"); - -$control = Mockery::mock(UI\Control::class); -$control->shouldReceive('getPresenter')->andReturn(null); -$control->shouldIgnoreMissing(); - -$factory = new ApplicationLatte\TemplateFactory($latteFactory); -$factory->createTemplate($control); - -$latte->setLoader(new Latte\Loaders\StringLoader); - -Assert::match( - '', - $latte->renderToString(''), -); diff --git a/tests/Bridges.Latte2/TemplateFactory.nonce.presenter.phpt b/tests/Bridges.Latte2/TemplateFactory.nonce.presenter.phpt deleted file mode 100644 index 1ef2df0e8..000000000 --- a/tests/Bridges.Latte2/TemplateFactory.nonce.presenter.phpt +++ /dev/null @@ -1,42 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - -Tester\Environment::bypassFinals(); - -$latte = new Latte\Engine; - -$latteFactory = Mockery::mock(ApplicationLatte\LatteFactory::class); -$latteFactory->shouldReceive('create')->andReturn($latte); - -$response = Mockery::mock(Nette\Http\IResponse::class); -$response->shouldReceive('getHeader')->with('Content-Security-Policy')->andReturn("hello 'nonce-abcd123==' world"); - -$presenter = Mockery::mock(UI\Presenter::class); -$presenter->shouldReceive('getPresenterIfExists')->andReturn($presenter); -$presenter->shouldReceive('getHttpResponse')->andReturn($response); -$presenter->shouldIgnoreMissing(); - -$factory = new ApplicationLatte\TemplateFactory($latteFactory); -$factory->createTemplate($presenter); - -$latte->setLoader(new Latte\Loaders\StringLoader); - -Assert::match( - '', - $latte->renderToString(''), -); diff --git a/tests/Bridges.Latte2/TemplateFactory.onCompile.phpt b/tests/Bridges.Latte2/TemplateFactory.onCompile.phpt deleted file mode 100644 index b60ebd8e1..000000000 --- a/tests/Bridges.Latte2/TemplateFactory.onCompile.phpt +++ /dev/null @@ -1,80 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -test('', function () { - $engine = new Latte\Engine; - $latteFactory = Mockery::mock(LatteFactory::class); - $latteFactory->shouldReceive('create')->andReturn($engine); - $factory = new TemplateFactory($latteFactory, new Http\Request(new Http\UrlScript('http://nette.org'))); - $engine->onCompile[] = $callback = function () {}; - - $factory->createTemplate(); - - Assert::type('array', $engine->onCompile); - Assert::type(Closure::class, $engine->onCompile[0]); // prepended by TemplateFactory - Assert::same($callback, $engine->onCompile[1]); // our callback -}); - - -test('', function () { - $engine = new Latte\Engine; - $latteFactory = Mockery::mock(LatteFactory::class); - $latteFactory->shouldReceive('create')->andReturn($engine); - $factory = new TemplateFactory($latteFactory, new Http\Request(new Http\UrlScript('http://nette.org'))); - $engine->onCompile = new ArrayIterator([$callback = function () {}]); - - $factory->createTemplate(); - - Assert::type('array', $engine->onCompile); - Assert::type(Closure::class, $engine->onCompile[0]); // prepended by TemplateFactory - Assert::same($callback, $engine->onCompile[1]); // our callback -}); - - -test('', function () { - class Event implements IteratorAggregate - { - public $events; - - - public function __construct($events) - { - $this->events = $events; - } - - - public function getIterator(): ArrayIterator - { - return new ArrayIterator($this->events); - } - } - - $engine = new Latte\Engine; - $latteFactory = Mockery::mock(LatteFactory::class); - $latteFactory->shouldReceive('create')->andReturn($engine); - $factory = new TemplateFactory($latteFactory, new Http\Request(new Http\UrlScript('http://nette.org'))); - $engine->onCompile = new Event([$callback = function () {}]); - - $factory->createTemplate(); - - Assert::type('array', $engine->onCompile); - Assert::type(Closure::class, $engine->onCompile[0]); // prepended by TemplateFactory - Assert::same($callback, $engine->onCompile[1]); // our callback -}); diff --git a/tests/Bridges.Latte2/TemplateFactory.onCreate.phpt b/tests/Bridges.Latte2/TemplateFactory.onCreate.phpt deleted file mode 100644 index 8f86ef42d..000000000 --- a/tests/Bridges.Latte2/TemplateFactory.onCreate.phpt +++ /dev/null @@ -1,36 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -test('', function () { - $engine = new Latte\Engine; - $latteFactory = Mockery::mock(LatteFactory::class); - $latteFactory->shouldReceive('create')->andReturn($engine); - $factory = new TemplateFactory($latteFactory, new Http\Request(new Http\UrlScript('http://nette.org'))); - $factory->onCreate[] = $callback = function (Template $template) { - $template->add('foo', 'bar'); - }; - - $template = $factory->createTemplate(); - - Assert::type('array', $factory->onCreate); - Assert::same($callback, $factory->onCreate[0]); // our callback - Assert::equal('bar', $template->foo); -}); diff --git a/tests/Bridges.Latte2/UIMacros.control.2.phpt b/tests/Bridges.Latte2/UIMacros.control.2.phpt deleted file mode 100644 index 9449e00e3..000000000 --- a/tests/Bridges.Latte2/UIMacros.control.2.phpt +++ /dev/null @@ -1,86 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -class MockComponent -{ - public function getComponent($name) - { - Notes::add(__METHOD__); - Notes::add(func_get_args()); - return new MockControl; - } -} - - -class MockControl -{ - public function __call($name, $args) - { - Notes::add(__METHOD__); - Notes::add(func_get_args()); - } -} - - -$latte = new Latte\Engine; -$latte->setLoader(new Latte\Loaders\StringLoader); -UIMacros::install($latte->getCompiler()); - -$latte->addProvider('uiControl', new MockComponent); -$params['form'] = new MockControl; -$params['name'] = 'form'; - -$latte->renderToString(' -{control \'name\'} - -{control form} - -{control form:test} - -{control $form:test} - -{control $name:test} - -{control $name:$name} - -{control form var1} - -{control form var1, 1, 2} - -{control form var1 => 5, 1, 2} -', $params); - -Assert::same([ - 'MockComponent::getComponent', ['name'], - 'MockControl::__call', ['render', []], - 'MockComponent::getComponent', ['form'], - 'MockControl::__call', ['render', []], - 'MockComponent::getComponent', ['form'], - 'MockControl::__call', ['renderTest', []], - 'MockControl::__call', ['renderTest', []], - 'MockComponent::getComponent', ['form'], - 'MockControl::__call', ['renderTest', []], - 'MockComponent::getComponent', ['form'], - 'MockControl::__call', ['renderform', []], - 'MockComponent::getComponent', ['form'], - 'MockControl::__call', ['render', ['var1']], - 'MockComponent::getComponent', ['form'], - 'MockControl::__call', ['render', ['var1', 1, 2]], - 'MockComponent::getComponent', ['form'], - 'MockControl::__call', ['render', [['var1' => 5, 0 => 1, 1 => 2]]], -], Notes::fetch()); diff --git a/tests/Bridges.Latte2/UIMacros.control.3.phpt b/tests/Bridges.Latte2/UIMacros.control.3.phpt deleted file mode 100644 index f5d6e23d2..000000000 --- a/tests/Bridges.Latte2/UIMacros.control.3.phpt +++ /dev/null @@ -1,51 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -$latte = new Latte\Engine; -$latte->setLoader(new Latte\Loaders\StringLoader); -UIMacros::install($latte->getCompiler()); -$latte->addProvider('uiControl', new class { - public function render() - { - echo '<>&'; - } - - - public function __call($name, $args) - { - return new self; - } -}); - -Assert::exception(function () use ($latte) { - $latte->renderToString('
&', - $latte->renderToString('
', - $latte->renderToString('
'), -); - -Assert::exception(function () use ($latte) { - $latte->renderToString(''); -}, Latte\RuntimeException::class, 'Filters: unable to convert content type HTML to HTMLCSS'); diff --git a/tests/Bridges.Latte2/UIMacros.control.phpt b/tests/Bridges.Latte2/UIMacros.control.phpt deleted file mode 100644 index 559895322..000000000 --- a/tests/Bridges.Latte2/UIMacros.control.phpt +++ /dev/null @@ -1,88 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -$latte = new Latte\Engine; -$latte->setLoader(new Latte\Loaders\StringLoader); -UIMacros::install($latte->getCompiler()); - -// {control ...} -Assert::match( - '%A% $this->global->uiControl->getComponent("form");%A%->render();%A%', - $latte->compile('{control form}'), -); - -@Assert::match( - <<<'XX' - %A% - /* line 1 */ $_tmp = $this->global->uiControl->getComponent("form"); - if ($_tmp instanceof Nette\Application\UI\Renderable) $_tmp->redrawControl(null, false); - ob_start(fn() => null); - $_tmp->render(); - $ʟ_fi = new LR\FilterInfo('html'); - echo $this->filters->filterContent('filter', $ʟ_fi, ob_get_clean()); - %A% - XX, - $latte->compile('{control form|filter}'), -); // @deprecated - -Assert::match( - <<<'XX' - %A% - /* line 1 */ if (is_object($form)) $_tmp = $form; - else $_tmp = $this->global->uiControl->getComponent($form); - if ($_tmp instanceof Nette\Application\UI\Renderable) $_tmp->redrawControl(null, false); - $_tmp->render(); - %A% - XX, - $latte->compile('{control $form}'), -); - -Assert::match( - '%A% $this->global->uiControl->getComponent("form");%A%->renderType();%A%', - $latte->compile('{control form:type}'), -); - -Assert::match( - '%A% $this->global->uiControl->getComponent("form");%A%->{"render$type"}();%A%', - $latte->compile('{control form:$type}'), -); - -Assert::match( - '%A% $this->global->uiControl->getComponent("form");%A%->renderType(\'param\');%A%', - $latte->compile('{control form:type param}'), -); - -Assert::match( - '%A% $this->global->uiControl->getComponent("form");%A%->render(array_merge([], $params, []));%A%', - $latte->compile('{control form (expand) $params}'), -); - -Assert::match( - '%A% $this->global->uiControl->getComponent("form");%A%->renderType([\'param\' => 123]);%A%', - $latte->compile('{control form:type param => 123}'), -); - -Assert::match( - '%A% $this->global->uiControl->getComponent("form");%A%->renderType([\'param\' => 123]);%A%', - $latte->compile('{control form:type, param => 123}'), -); - -Assert::match( - '%A% $this->global->uiControl->getComponent("form");%A%->renderType(param: 123);%A%', - $latte->compile('{control form:type, param: 123}'), -); diff --git a/tests/Bridges.Latte2/UIMacros.isLinkCurrent.phpt b/tests/Bridges.Latte2/UIMacros.isLinkCurrent.phpt deleted file mode 100644 index 579a8fd4b..000000000 --- a/tests/Bridges.Latte2/UIMacros.isLinkCurrent.phpt +++ /dev/null @@ -1,54 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - -Tester\Environment::bypassFinals(); - -$latte = new Latte\Engine; - -$latteFactory = Mockery::mock(Nette\Bridges\ApplicationLatte\LatteFactory::class); -$latteFactory->shouldReceive('create')->andReturn($latte); - -$presenter = Mockery::mock(Nette\Application\UI\Presenter::class); -$presenter->shouldReceive('getPresenterIfExists')->andReturn($presenter); -$presenter->shouldReceive('getHttpResponse')->andReturn((Mockery::mock(Nette\Http\IResponse::class))->shouldIgnoreMissing()); -$presenter->shouldIgnoreMissing(); - -$factory = new Nette\Bridges\ApplicationLatte\TemplateFactory($latteFactory); -$factory->createTemplate($presenter); - -$latte->setLoader(new Latte\Loaders\StringLoader); - -Assert::matchFile( - __DIR__ . '/expected/UIMacros.isLinkCurrent.php', - $latte->compile( - <<<'XX' - n:href before n:class - - n:href after n:class - - href before n:class - - href after n:class - - {ifCurrent}empty{/ifCurrent} - - {ifCurrent default}default{/ifCurrent} - - custom function - - XX, - ), -); diff --git a/tests/Bridges.Latte2/UIMacros.link.2.phpt b/tests/Bridges.Latte2/UIMacros.link.2.phpt deleted file mode 100644 index 83a441c31..000000000 --- a/tests/Bridges.Latte2/UIMacros.link.2.phpt +++ /dev/null @@ -1,122 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -class MockControl -{ - public function link($destination, $args = []) - { - if (!is_array($args)) { - $args = array_slice(func_get_args(), 1); - } - - array_unshift($args, $destination); - return 'link:' . strtr(json_encode($args), '"', "'"); - } -} - - -class MockPresenter extends MockControl -{ - public function link($destination, $args = []) - { - if (!is_array($args)) { - $args = array_slice(func_get_args(), 1); - } - - array_unshift($args, $destination); - return 'plink:' . strtr(json_encode($args), '"', "'"); - } - - - public function isAjax() - { - return false; - } -} - - -$latte = new Latte\Engine; -$latte->setLoader(new Latte\Loaders\StringLoader); -UIMacros::install($latte->getCompiler()); - -$latte->addProvider('uiControl', new MockControl); -$latte->addProvider('uiPresenter', new MockPresenter); -$params['action'] = 'login'; -$params['arr'] = ['link' => 'login', 'param' => 123]; - -Assert::match(<<<'EOD' - plink:['Homepage:'] - - plink:['Homepage:'] - - plink:['Homepage:action'] - - plink:['Homepage:action'] - - plink:['Homepage:action',10,20,'{one}&two'] - - plink:['Homepage:action#hash',10,20,'{one}&two'] - - plink:['#hash'] - - plink:[':',10] - - plink:{'0':'default','1':10,'a':20,'b':30} - - link:['login'] - - - - - - - - - - - EOD, strtr($latte->renderToString(<<<'EOD' - {plink Homepage:} - - {plink Homepage: } - - {plink Homepage:action } - - {plink 'Homepage:action' } - - {plink Homepage:action 10, 20, '{one}&two'} - - {plink Homepage:action#hash 10, 20, '{one}&two'} - - {plink #hash} - - {plink : 10 } - - {plink default 10, 'a' => 20, 'b' => 30} - - {link $action} - - - - - - - - - - - EOD, $params), [''' => "'", ''' => "'", '{' => '{'])); diff --git a/tests/Bridges.Latte2/UIMacros.link.phpt b/tests/Bridges.Latte2/UIMacros.link.phpt deleted file mode 100644 index 52fda3fb0..000000000 --- a/tests/Bridges.Latte2/UIMacros.link.phpt +++ /dev/null @@ -1,68 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -$latte = new Latte\Engine; -$latte->setLoader(new Latte\Loaders\StringLoader); -UIMacros::install($latte->getCompiler()); - -// {link ...} -Assert::contains( - '$this->global->uiControl->link("p")', - $latte->compile('{link p}'), -); -Assert::contains( - '($this->filters->filter)($this->global->uiControl->link("p"))', - $latte->compile('{link p|filter}'), -); -Assert::contains( - '$this->global->uiControl->link("p:a")', - $latte->compile('{link p:a}'), -); -Assert::contains( - '$this->global->uiControl->link($dest)', - $latte->compile('{link $dest}'), -); -Assert::contains( - '$this->global->uiControl->link($p:$a)', - $latte->compile('{link $p:$a}'), -); -Assert::contains( - '$this->global->uiControl->link("$p:$a")', - $latte->compile('{link "$p:$a"}'), -); -Assert::contains( - '$this->global->uiControl->link("p:a")', - $latte->compile('{link "p:a"}'), -); -Assert::contains( - '$this->global->uiControl->link(\'p:a\')', - $latte->compile('{link \'p:a\'}'), -); - -Assert::contains( - '$this->global->uiControl->link("p", [\'param\'])', - $latte->compile('{link p param}'), -); -Assert::contains( - '$this->global->uiControl->link("p", [\'param\' => 123])', - $latte->compile('{link p param => 123}'), -); -Assert::contains( - '$this->global->uiControl->link("p", [\'param\' => 123])', - $latte->compile('{link p, param => 123}'), -); diff --git a/tests/Bridges.Latte2/UIMacros.renderSnippets.phpt b/tests/Bridges.Latte2/UIMacros.renderSnippets.phpt deleted file mode 100644 index 71c354140..000000000 --- a/tests/Bridges.Latte2/UIMacros.renderSnippets.phpt +++ /dev/null @@ -1,97 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -class InnerControl extends Nette\Application\UI\Control -{ - public function render() - { - $latte = new Latte\Engine; - UIMacros::install($latte->getCompiler()); - $latte->addProvider('uiPresenter', $this->getPresenter()); - $latte->addProvider('uiControl', $this); - $latte->addProvider('snippetBridge', new Nette\Bridges\ApplicationLatte\SnippetBridge($this)); - $params['say'] = 'Hello'; - $latte->render(__DIR__ . '/templates/snippet-included.latte', $params); - } -} - -class TestPresenter extends Nette\Application\UI\Presenter -{ - public function createComponentMulti() - { - return new Nette\Application\UI\Multiplier(function () { - $control = new InnerControl; - $control->redrawControl(); - return $control; - }); - } - - - public function render() - { - $latte = new Latte\Engine; - UIMacros::install($latte->getCompiler()); - $latte->addProvider('snippetBridge', new Nette\Bridges\ApplicationLatte\SnippetBridge($this)); - $latte->render(__DIR__ . '/templates/snippet-include.latte'); - } -} - - -$presenter = new TestPresenter; -$presenter->snippetMode = true; -$presenter->redrawControl(); -$presenter['multi-1']->redrawControl(); -$presenter->render(); -Assert::same([ - 'snippets' => [ - 'snippet--hello' => 'Hello', - 'snippet--include' => "

Included file #3 (A, B)

\n", - 'snippet--array-1' => 'Value 1', - 'snippet--array-2' => 'Value 2', - 'snippet--array-3' => 'Value 3', - 'snippet--array2-1' => 'Value 1', - 'snippet--array2-2' => 'Value 2', - 'snippet--array2-3' => 'Value 3', - 'snippet--includeSay' => 'Hello include snippet', - 'snippet--nested1' => "\t
Foo
\n", - 'snippet-multi-1-includeSay' => 'Hello', - ], -], (array) $presenter->payload); - - - -$presenter = new TestPresenter; -$presenter->snippetMode = true; -$presenter->redrawControl('hello'); -$presenter->redrawControl('array'); -$presenter->render(); - -Assert::same([ - 'snippets' => [ - 'snippet--hello' => 'Hello', - 'snippet--array-1' => 'Value 1', - 'snippet--array-2' => 'Value 2', - 'snippet--array-3' => 'Value 3', - ], -], (array) $presenter->payload); - -$presenter = new TestPresenter; -ob_start(); -$presenter->render(); -$content = ob_get_clean(); -Assert::matchFile(__DIR__ . '/expected/UIMacros.renderSnippets.html', $content); diff --git a/tests/Bridges.Latte2/UIMacros.renderSnippets2.phpt b/tests/Bridges.Latte2/UIMacros.renderSnippets2.phpt deleted file mode 100644 index 58a72d170..000000000 --- a/tests/Bridges.Latte2/UIMacros.renderSnippets2.phpt +++ /dev/null @@ -1,84 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -class InnerControl extends Nette\Application\UI\Control -{ - public function render() - { - $this->renderA(); - $this->renderB(); - } - - - public function renderA() - { - $latte = new Latte\Engine; - $latte->setLoader(new Latte\Loaders\StringLoader); - UIMacros::install($latte->getCompiler()); - $latte->addProvider('uiPresenter', $this->getPresenter()); - $latte->addProvider('uiControl', $this); - $latte->addProvider('snippetBridge', new SnippetBridge($this)); - $params['say'] = 'Hello'; - $latte->render('{snippet testA}{$say}{/snippet}', $params); - } - - - public function renderB() - { - $latte = new Latte\Engine; - $latte->setLoader(new Latte\Loaders\StringLoader); - UIMacros::install($latte->getCompiler()); - $latte->addProvider('uiPresenter', $this->getPresenter()); - $latte->addProvider('uiControl', $this); - $latte->addProvider('snippetBridge', new SnippetBridge($this)); - $params['say'] = 'world'; - $latte->render('{snippet testB}{$say}{/snippet}', $params); - } -} - -class TestPresenter extends Nette\Application\UI\Presenter -{ - public function createComponentMulti() - { - return new Nette\Application\UI\Multiplier(fn() => new InnerControl); - } - - - public function render() - { - $latte = new Latte\Engine; - $latte->setLoader(new Latte\Loaders\StringLoader); - UIMacros::install($latte->getCompiler()); - $latte->addProvider('uiControl', $this); - $latte->addProvider('snippetBridge', new SnippetBridge($this)); - $latte->render(''); - } -} - - -$presenter = new TestPresenter; -$presenter->snippetMode = true; -$presenter['multi-1']->redrawControl(); -$presenter->render(); -Assert::same([ - 'snippets' => [ - 'snippet-multi-1-testA' => 'Hello', - 'snippet-multi-1-testB' => 'world', - ], -], (array) $presenter->payload); diff --git a/tests/Bridges.Latte2/UIMacros.renderSnippets3.phpt b/tests/Bridges.Latte2/UIMacros.renderSnippets3.phpt deleted file mode 100644 index 3dc72672b..000000000 --- a/tests/Bridges.Latte2/UIMacros.renderSnippets3.phpt +++ /dev/null @@ -1,73 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -class TestControl extends Nette\Application\UI\Control -{ - public function render() - { - $latte = new Latte\Engine; - $latte->setLoader(new Latte\Loaders\StringLoader); - UIMacros::install($latte->getCompiler()); - $latte->addProvider('uiPresenter', $this->getPresenter()); - $latte->addProvider('uiControl', $this); - $latte->addProvider('snippetBridge', new Nette\Bridges\ApplicationLatte\SnippetBridge($this)); - $latte->render('{snippet foo}hello{/snippet}'); - } -} - -class TestPresenter extends Nette\Application\UI\Presenter -{ - public function createComponentTest() - { - return new TestControl; - } - - - public function render() - { - $latte = new Latte\Engine; - $latte->setLoader(new Latte\Loaders\StringLoader); - UIMacros::install($latte->getCompiler()); - $latte->addProvider('uiControl', $this); - $latte->addProvider('snippetBridge', new Nette\Bridges\ApplicationLatte\SnippetBridge($this)); - $latte->render('{snippet foo}{control test}{/snippet}'); - } -} - - -$presenter = new TestPresenter; -$presenter->snippetMode = true; -$presenter->redrawControl('foo'); -$presenter['test']->redrawControl('foo'); -$presenter->render(); -Assert::same([ - 'snippets' => [ - 'snippet--foo' => '
hello
', - ], -], (array) $presenter->payload); - - -$presenter = new TestPresenter; -$presenter->snippetMode = true; -$presenter['test']->redrawControl('foo'); -$presenter->render(); -Assert::same([ - 'snippets' => [ - 'snippet-test-foo' => 'hello', - ], -], (array) $presenter->payload); diff --git a/tests/Bridges.Latte2/UIMacros.renderSnippets4.phpt b/tests/Bridges.Latte2/UIMacros.renderSnippets4.phpt deleted file mode 100644 index 917404369..000000000 --- a/tests/Bridges.Latte2/UIMacros.renderSnippets4.phpt +++ /dev/null @@ -1,54 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - - -class TestPresenter extends Nette\Application\UI\Presenter -{ - public function render() - { - $latte = new Latte\Engine; - $latte->setLoader(new Latte\Loaders\StringLoader); - UIMacros::install($latte->getCompiler()); - $latte->addProvider('uiControl', $this); - $latte->addProvider('snippetBridge', new SnippetBridge($this)); - $latte->render('{snippet foo}{php $presenter->renderFoo()}{/snippet}', ['presenter' => $this]); - } - - - public function renderFoo() - { - $latte = new Latte\Engine; - $latte->setLoader(new Latte\Loaders\StringLoader); - UIMacros::install($latte->getCompiler()); - $latte->addProvider('uiControl', $this); - $latte->addProvider('snippetBridge', new SnippetBridge($this)); - $latte->render('Hello'); - } -} - - -$presenter = new TestPresenter; -$presenter->snippetMode = true; -$presenter->redrawControl('foo'); -$presenter->render(); -Assert::same([ - 'snippets' => [ - 'snippet--foo' => 'Hello', - ], -], (array) $presenter->payload); diff --git a/tests/Bridges.Latte2/UIMacros.renderSnippets5.phpt b/tests/Bridges.Latte2/UIMacros.renderSnippets5.phpt deleted file mode 100644 index a915657fe..000000000 --- a/tests/Bridges.Latte2/UIMacros.renderSnippets5.phpt +++ /dev/null @@ -1,59 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - - -class TestPresenter extends Nette\Application\UI\Presenter -{ - public function render(string $template) - { - $latte = new Latte\Engine; - $latte->setLoader(new Latte\Loaders\StringLoader); - UIMacros::install($latte->getCompiler()); - $latte->addProvider('uiControl', $this); - $latte->addProvider('snippetBridge', new SnippetBridge($this)); - $latte->render($template, ['presenter' => $this]); - } -} - - -$presenter = new TestPresenter; -$presenter->snippetMode = true; -$presenter->redrawControl('foo'); -$presenter->render('
Hello
'); -Assert::same([ - 'snippets' => [ - 'snippet--foo' => 'Hello', - ], -], (array) $presenter->payload); - - -$presenter = new TestPresenter; -$presenter->snippetMode = true; -$presenter->redrawControl('foo'); -Assert::exception(function () use ($presenter) { - $presenter->render('
Hello
'); -}, Latte\CompileException::class, 'Cannot combine HTML attribute id with n:snippet.'); - - -$presenter = new TestPresenter; -$presenter->snippetMode = true; -$presenter->redrawControl('foo'); -Assert::exception(function () use ($presenter) { - $presenter->render('
Hello
'); -}, Latte\CompileException::class, 'Cannot combine HTML attribute id with n:snippet.'); diff --git a/tests/Bridges.Latte2/UIMacros.renderSnippets6.phpt b/tests/Bridges.Latte2/UIMacros.renderSnippets6.phpt deleted file mode 100644 index dc4e32a25..000000000 --- a/tests/Bridges.Latte2/UIMacros.renderSnippets6.phpt +++ /dev/null @@ -1,45 +0,0 @@ -')) { - Tester\Environment::skip('Test for Latte 2'); -} - - -class TestPresenter extends Nette\Application\UI\Presenter -{ - public function render(string $template) - { - $latte = new Latte\Engine; - $latte->setLoader(new Latte\Loaders\StringLoader); - UIMacros::install($latte->getCompiler()); - $latte->addProvider('snippetBridge', new Nette\Bridges\ApplicationLatte\SnippetBridge($this)); - $latte->onCompile[] = function ($latte) { - $latte->getCompiler()->getMacros()['snippet'][0]->snippetAttribute = 'data-snippet'; - }; - $latte->render($template); - } -} - - -$presenter = new TestPresenter; -ob_start(); -$presenter->render('
hello
'); -$content = ob_get_clean(); -Assert::same('
hello
', $content); - - -$presenter = new TestPresenter; -Assert::exception(function () use ($presenter) { - $presenter->render('
hello
'); -}, Latte\CompileException::class, 'Cannot combine HTML attribute data-snippet with n:snippet.'); diff --git a/tests/Bridges.Latte2/expected/UIMacros.isLinkCurrent.php b/tests/Bridges.Latte2/expected/UIMacros.isLinkCurrent.php deleted file mode 100644 index 15ef390af..000000000 --- a/tests/Bridges.Latte2/expected/UIMacros.isLinkCurrent.php +++ /dev/null @@ -1,22 +0,0 @@ -%A%n:href before n:class - -n:href after n:class - -href before n:class - -href after n:class - -'; - if ($this->global->uiPresenter->getLastCreatedRequestFlag("current")) { - echo 'empty'; - } - echo ' - -'; - if ($this->global->uiPresenter->isLinkCurrent("default")) { - echo 'default'; - } - echo ' - -global->fn->isLinkCurrent)('default') ? 'current' : null%A%>custom function -%A% diff --git a/tests/Bridges.Latte2/expected/UIMacros.renderSnippets.html b/tests/Bridges.Latte2/expected/UIMacros.renderSnippets.html deleted file mode 100644 index 3ff3683ed..000000000 --- a/tests/Bridges.Latte2/expected/UIMacros.renderSnippets.html +++ /dev/null @@ -1,20 +0,0 @@ -
Hello
world! - -

Included file #3 (A, B)

-
- -
Value 1
-
Value 2
-
Value 3
-
- -
Value 1
-
Value 2
-
Value 3
- - -
Hello include snippet
- - -
Foo
-
diff --git a/tests/Bridges.Latte2/templates/include3.latte b/tests/Bridges.Latte2/templates/include3.latte deleted file mode 100644 index 14caf4cb4..000000000 --- a/tests/Bridges.Latte2/templates/include3.latte +++ /dev/null @@ -1 +0,0 @@ -

Included file #3 ({$localvar}, {$hello})

diff --git a/tests/Bridges.Latte2/templates/snippet-include.latte b/tests/Bridges.Latte2/templates/snippet-include.latte deleted file mode 100644 index 8a1ec964d..000000000 --- a/tests/Bridges.Latte2/templates/snippet-include.latte +++ /dev/null @@ -1,25 +0,0 @@ -{snippet hello}Hello{/snippet} world! - -{snippet include} - {include include3.latte localvar => 'A', hello => 'B'} -{/snippet} - -{snippet array} - {foreach [1, 2, 3] as $id} - {snippet "array-$id"}Value {$id}{/snippet} - {/foreach} -{/snippet} - -{snippetArea array2} - {foreach [1, 2, 3] as $id} - {snippet "array2-$id"}Value {$id}{/snippet} - {/foreach} -{/snippetArea} - -{snippetArea foo} - {include snippet-included.latte say => 'Hello include snippet'} -{/snippetArea} - -{snippet nested1} - {snippet nested2}Foo{/snippet} -{/snippet} diff --git a/tests/Bridges.Latte2/templates/snippet-included.latte b/tests/Bridges.Latte2/templates/snippet-included.latte deleted file mode 100644 index a392b6227..000000000 --- a/tests/Bridges.Latte2/templates/snippet-included.latte +++ /dev/null @@ -1 +0,0 @@ -{snippet includeSay}{$say}{/snippet} diff --git a/tests/Bridges.Latte3/Template.getParentName().phpt b/tests/Bridges.Latte3/Template.getParentName().phpt index b354ad1ee..e63f523eb 100644 --- a/tests/Bridges.Latte3/Template.getParentName().phpt +++ b/tests/Bridges.Latte3/Template.getParentName().phpt @@ -6,10 +6,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - Tester\Environment::bypassFinals(); $presenter = Mockery::mock(Nette\Application\UI\Presenter::class) diff --git a/tests/Bridges.Latte3/TemplateFactory.customTemplate.phpt b/tests/Bridges.Latte3/TemplateFactory.customTemplate.phpt index 976f99b78..a76c9d50e 100644 --- a/tests/Bridges.Latte3/TemplateFactory.customTemplate.phpt +++ b/tests/Bridges.Latte3/TemplateFactory.customTemplate.phpt @@ -14,10 +14,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - Tester\Environment::bypassFinals(); diff --git a/tests/Bridges.Latte3/TemplateFactory.onCreate.phpt b/tests/Bridges.Latte3/TemplateFactory.onCreate.phpt index ed6e9b61c..987e86aea 100644 --- a/tests/Bridges.Latte3/TemplateFactory.onCreate.phpt +++ b/tests/Bridges.Latte3/TemplateFactory.onCreate.phpt @@ -14,10 +14,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - test('', function () { $engine = new Latte\Engine; diff --git a/tests/Bridges.Latte3/UIExtension.filters.phpt b/tests/Bridges.Latte3/UIExtension.filters.phpt index 952f5a760..0dc89f8cd 100644 --- a/tests/Bridges.Latte3/UIExtension.filters.phpt +++ b/tests/Bridges.Latte3/UIExtension.filters.phpt @@ -10,10 +10,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $latte = new Latte\Engine; $latte->addExtension(new Nette\Bridges\ApplicationLatte\UIExtension(null)); diff --git a/tests/Bridges.Latte3/UIExtension.nonce.control.phpt b/tests/Bridges.Latte3/UIExtension.nonce.control.phpt index 9248da8af..cf822c0ab 100644 --- a/tests/Bridges.Latte3/UIExtension.nonce.control.phpt +++ b/tests/Bridges.Latte3/UIExtension.nonce.control.phpt @@ -11,10 +11,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $response = Mockery::mock(Nette\Http\IResponse::class); $response->shouldReceive('getHeader')->with('Content-Security-Policy')->andReturn("hello 'nonce-abcd123==' world"); diff --git a/tests/Bridges.Latte3/UIExtension.nonce.presenter.phpt b/tests/Bridges.Latte3/UIExtension.nonce.presenter.phpt index 2f2a8d254..15f0d212d 100644 --- a/tests/Bridges.Latte3/UIExtension.nonce.presenter.phpt +++ b/tests/Bridges.Latte3/UIExtension.nonce.presenter.phpt @@ -11,10 +11,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - Tester\Environment::bypassFinals(); $response = Mockery::mock(Nette\Http\IResponse::class); diff --git a/tests/Bridges.Latte3/isLinkCurrent().phpt b/tests/Bridges.Latte3/isLinkCurrent().phpt index 1ca37dcb3..277027dc9 100644 --- a/tests/Bridges.Latte3/isLinkCurrent().phpt +++ b/tests/Bridges.Latte3/isLinkCurrent().phpt @@ -10,10 +10,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - Tester\Environment::bypassFinals(); $presenter = Mockery::mock(Nette\Application\UI\Presenter::class); diff --git a/tests/Bridges.Latte3/n-snippet.2.phpt b/tests/Bridges.Latte3/n-snippet.2.phpt index 983c46ce5..a5cfc2a20 100644 --- a/tests/Bridges.Latte3/n-snippet.2.phpt +++ b/tests/Bridges.Latte3/n-snippet.2.phpt @@ -6,10 +6,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $latte = new Latte\Engine; $latte->setLoader(new Latte\Loaders\StringLoader); $latte->addExtension(new Nette\Bridges\ApplicationLatte\UIExtension(null)); diff --git a/tests/Bridges.Latte3/n-snippet.block.phpt b/tests/Bridges.Latte3/n-snippet.block.phpt index 107dd6ebc..27a83c2f7 100644 --- a/tests/Bridges.Latte3/n-snippet.block.phpt +++ b/tests/Bridges.Latte3/n-snippet.block.phpt @@ -6,10 +6,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $latte = new Latte\Engine; $latte->setLoader(new Latte\Loaders\StringLoader); diff --git a/tests/Bridges.Latte3/n-snippet.dynamic.phpt b/tests/Bridges.Latte3/n-snippet.dynamic.phpt index ab2827bca..a794e2d0c 100644 --- a/tests/Bridges.Latte3/n-snippet.dynamic.phpt +++ b/tests/Bridges.Latte3/n-snippet.dynamic.phpt @@ -6,10 +6,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $latte = new Latte\Engine; $latte->setLoader(new Latte\Loaders\StringLoader); diff --git a/tests/Bridges.Latte3/n-snippet.phpt b/tests/Bridges.Latte3/n-snippet.phpt index c9ff1b893..ac2247eec 100644 --- a/tests/Bridges.Latte3/n-snippet.phpt +++ b/tests/Bridges.Latte3/n-snippet.phpt @@ -6,9 +6,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} class Test { diff --git a/tests/Bridges.Latte3/renderSnippets.phpt b/tests/Bridges.Latte3/renderSnippets.phpt index 675995784..4d113171f 100644 --- a/tests/Bridges.Latte3/renderSnippets.phpt +++ b/tests/Bridges.Latte3/renderSnippets.phpt @@ -11,10 +11,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - class InnerControl extends Nette\Application\UI\Control { diff --git a/tests/Bridges.Latte3/renderSnippets2.phpt b/tests/Bridges.Latte3/renderSnippets2.phpt index 31522dbee..1a092d470 100644 --- a/tests/Bridges.Latte3/renderSnippets2.phpt +++ b/tests/Bridges.Latte3/renderSnippets2.phpt @@ -11,10 +11,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - class InnerControl extends Nette\Application\UI\Control { diff --git a/tests/Bridges.Latte3/renderSnippets3.phpt b/tests/Bridges.Latte3/renderSnippets3.phpt index dd11322d4..65a621014 100644 --- a/tests/Bridges.Latte3/renderSnippets3.phpt +++ b/tests/Bridges.Latte3/renderSnippets3.phpt @@ -11,10 +11,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - class TestControl extends Nette\Application\UI\Control { diff --git a/tests/Bridges.Latte3/renderSnippets4.phpt b/tests/Bridges.Latte3/renderSnippets4.phpt index 3bf12a6e5..c209301c6 100644 --- a/tests/Bridges.Latte3/renderSnippets4.phpt +++ b/tests/Bridges.Latte3/renderSnippets4.phpt @@ -11,10 +11,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - class TestPresenter extends Nette\Application\UI\Presenter { diff --git a/tests/Bridges.Latte3/renderSnippets5.phpt b/tests/Bridges.Latte3/renderSnippets5.phpt index fdbd86159..340e36cf6 100644 --- a/tests/Bridges.Latte3/renderSnippets5.phpt +++ b/tests/Bridges.Latte3/renderSnippets5.phpt @@ -11,10 +11,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - class TestPresenter extends Nette\Application\UI\Presenter { diff --git a/tests/Bridges.Latte3/renderSnippets6.phpt b/tests/Bridges.Latte3/renderSnippets6.phpt index f264135e7..a9cda7417 100644 --- a/tests/Bridges.Latte3/renderSnippets6.phpt +++ b/tests/Bridges.Latte3/renderSnippets6.phpt @@ -11,10 +11,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - class TestPresenter extends Nette\Application\UI\Presenter { diff --git a/tests/Bridges.Latte3/renderSnippets7.phpt b/tests/Bridges.Latte3/renderSnippets7.phpt index 63f3cb635..a7689c434 100644 --- a/tests/Bridges.Latte3/renderSnippets7.phpt +++ b/tests/Bridges.Latte3/renderSnippets7.phpt @@ -9,10 +9,6 @@ Tester\Environment::bypassFinals(); require __DIR__ . '/ControlMock.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $dataSets = [ diff --git a/tests/Bridges.Latte3/{control}.2.phpt b/tests/Bridges.Latte3/{control}.2.phpt index bb2cb9171..7086c7fd1 100644 --- a/tests/Bridges.Latte3/{control}.2.phpt +++ b/tests/Bridges.Latte3/{control}.2.phpt @@ -10,10 +10,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - class MockComponent { diff --git a/tests/Bridges.Latte3/{control}.3.phpt b/tests/Bridges.Latte3/{control}.3.phpt index 7a270383f..d9317b057 100644 --- a/tests/Bridges.Latte3/{control}.3.phpt +++ b/tests/Bridges.Latte3/{control}.3.phpt @@ -10,9 +10,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} $control = new class { public function render() diff --git a/tests/Bridges.Latte3/{control}.phpt b/tests/Bridges.Latte3/{control}.phpt index a1ba85e15..8d78e3546 100644 --- a/tests/Bridges.Latte3/{control}.phpt +++ b/tests/Bridges.Latte3/{control}.phpt @@ -10,10 +10,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $latte = new Latte\Engine; $latte->setLoader(new Latte\Loaders\StringLoader); diff --git a/tests/Bridges.Latte3/{ifCurrent}.phpt b/tests/Bridges.Latte3/{ifCurrent}.phpt index 3c9ee133e..0be5f05e2 100644 --- a/tests/Bridges.Latte3/{ifCurrent}.phpt +++ b/tests/Bridges.Latte3/{ifCurrent}.phpt @@ -6,10 +6,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - Tester\Environment::bypassFinals(); $latte = new Latte\Engine; diff --git a/tests/Bridges.Latte3/{link}.2.phpt b/tests/Bridges.Latte3/{link}.2.phpt index 816283b42..7fc270038 100644 --- a/tests/Bridges.Latte3/{link}.2.phpt +++ b/tests/Bridges.Latte3/{link}.2.phpt @@ -10,10 +10,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - class MockControl { diff --git a/tests/Bridges.Latte3/{link}.phpt b/tests/Bridges.Latte3/{link}.phpt index e2457c9a7..9d8e296e6 100644 --- a/tests/Bridges.Latte3/{link}.phpt +++ b/tests/Bridges.Latte3/{link}.phpt @@ -10,10 +10,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $latte = new Latte\Engine; $latte->setLoader(new Latte\Loaders\StringLoader); diff --git a/tests/Bridges.Latte3/{snippet}.dynamic.phpt b/tests/Bridges.Latte3/{snippet}.dynamic.phpt index 3b2068ed0..1eb5aacdd 100644 --- a/tests/Bridges.Latte3/{snippet}.dynamic.phpt +++ b/tests/Bridges.Latte3/{snippet}.dynamic.phpt @@ -6,10 +6,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $latte = new Latte\Engine; $latte->setLoader(new Latte\Loaders\StringLoader); diff --git a/tests/Bridges.Latte3/{snippet}.phpt b/tests/Bridges.Latte3/{snippet}.phpt index bf9022dce..5afa062ef 100644 --- a/tests/Bridges.Latte3/{snippet}.phpt +++ b/tests/Bridges.Latte3/{snippet}.phpt @@ -6,10 +6,6 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -if (version_compare(Latte\Engine::VERSION, '3', '<')) { - Tester\Environment::skip('Test for Latte 3'); -} - $latte = new Latte\Engine; $latte->setLoader(new Latte\Loaders\StringLoader); From 8965e93f0598c51a5f5b61a72fbc66cdfd47f637 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Fri, 15 Oct 2021 18:14:52 +0200 Subject: [PATCH 03/21] removed compatibility for old class names - inteface Nette\Application\IRouter replaced by Nette\Routing\Router --- src/Application/Routers/Route.php | 3 --- src/Application/Routers/RouteList.php | 3 --- src/Application/Routers/SimpleRouter.php | 3 --- src/Application/UI/Component.php | 3 --- src/Application/UI/ComponentReflection.php | 3 --- src/compatibility-intf.php | 11 --------- src/compatibility.php | 28 ---------------------- 7 files changed, 54 deletions(-) delete mode 100644 src/compatibility.php diff --git a/src/Application/Routers/Route.php b/src/Application/Routers/Route.php index ba611da0e..2e22d9679 100644 --- a/src/Application/Routers/Route.php +++ b/src/Application/Routers/Route.php @@ -187,6 +187,3 @@ public static function path2presenter(string $s): string return $s; } } - - -interface_exists(Nette\Application\IRouter::class); diff --git a/src/Application/Routers/RouteList.php b/src/Application/Routers/RouteList.php index 99e2a6d17..126c0d053 100644 --- a/src/Application/Routers/RouteList.php +++ b/src/Application/Routers/RouteList.php @@ -139,6 +139,3 @@ public function offsetUnset($index): void $this->modify($index, null); } } - - -interface_exists(Nette\Application\IRouter::class); diff --git a/src/Application/Routers/SimpleRouter.php b/src/Application/Routers/SimpleRouter.php index 35d2c8ad9..2f99c51ba 100644 --- a/src/Application/Routers/SimpleRouter.php +++ b/src/Application/Routers/SimpleRouter.php @@ -38,6 +38,3 @@ public function __construct(array|string $defaults = []) parent::__construct($defaults); } } - - -interface_exists(Nette\Application\IRouter::class); diff --git a/src/Application/UI/Component.php b/src/Application/UI/Component.php index f0efe3ed9..baf3616e4 100644 --- a/src/Application/UI/Component.php +++ b/src/Application/UI/Component.php @@ -378,6 +378,3 @@ public function error(string $message = '', int $httpCode = Nette\Http\IResponse throw new Nette\Application\BadRequestException($message, $httpCode); } } - - -class_exists(PresenterComponent::class); diff --git a/src/Application/UI/ComponentReflection.php b/src/Application/UI/ComponentReflection.php index 9886f9916..4f9cbbbf6 100644 --- a/src/Application/UI/ComponentReflection.php +++ b/src/Application/UI/ComponentReflection.php @@ -214,6 +214,3 @@ public static function combineArgs(\ReflectionFunctionAbstract $method, array $a return ParameterConverter::toArguments($method, $args); } } - - -class_exists(PresenterComponentReflection::class); diff --git a/src/compatibility-intf.php b/src/compatibility-intf.php index 5bee25bb1..0d5b2f8ff 100644 --- a/src/compatibility-intf.php +++ b/src/compatibility-intf.php @@ -9,17 +9,6 @@ namespace Nette\Application; -use Nette; - -if (false) { - /** @deprecated use Nette\Routing\Router */ - interface IRouter extends Nette\Routing\Router - { - } -} elseif (!interface_exists(IRouter::class)) { - class_alias(Nette\Routing\Router::class, IRouter::class); -} - if (false) { /** @deprecated use Nette\Application\Response */ interface IResponse extends Response diff --git a/src/compatibility.php b/src/compatibility.php deleted file mode 100644 index cf55aa4bc..000000000 --- a/src/compatibility.php +++ /dev/null @@ -1,28 +0,0 @@ - Date: Thu, 8 Feb 2024 21:39:57 +0100 Subject: [PATCH 04/21] added type hints (BC break) --- src/Application/UI/Component.php | 6 ++---- src/Application/UI/Presenter.php | 21 +++++++------------ .../ApplicationLatte/TemplateFactory.php | 3 +-- tests/UI/Component.redirect().phpt | 2 +- 4 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/Application/UI/Component.php b/src/Application/UI/Component.php index baf3616e4..aa469e551 100644 --- a/src/Application/UI/Component.php +++ b/src/Application/UI/Component.php @@ -335,10 +335,9 @@ public function isLinkCurrent(?string $destination = null, $args = []): bool * Redirect to another presenter, action or signal. * @param string $destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" * @param array|mixed $args - * @return never * @throws Nette\Application\AbortException */ - public function redirect(string $destination, $args = []): void + public function redirect(string $destination, $args = []): never { $args = func_num_args() < 3 && is_array($args) ? $args @@ -353,10 +352,9 @@ public function redirect(string $destination, $args = []): void * Permanently redirects to presenter, action or signal. * @param string $destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" * @param array|mixed $args - * @return never * @throws Nette\Application\AbortException */ - public function redirectPermanent(string $destination, $args = []): void + public function redirectPermanent(string $destination, $args = []): never { $args = func_num_args() < 3 && is_array($args) ? $args diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index 33a9a8b64..b3dd9cda0 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -470,9 +470,8 @@ public function setLayout(string|bool $layout): static /** * @throws Nette\Application\AbortException - * @return never */ - public function sendTemplate(?Template $template = null): void + public function sendTemplate(?Template $template = null): never { $template ??= $this->getTemplate(); if (!$template->getFile()) { @@ -644,9 +643,8 @@ public function isAjax(): bool /** * Sends AJAX payload to the output. * @throws Nette\Application\AbortException - * @return never */ - public function sendPayload(): void + public function sendPayload(): never { $this->sendResponse(new Responses\JsonResponse($this->getPayload())); } @@ -655,9 +653,8 @@ public function sendPayload(): void /** * Sends JSON data to the output. * @throws Nette\Application\AbortException - * @return never */ - public function sendJson(mixed $data): void + public function sendJson(mixed $data): never { $this->sendResponse(new Responses\JsonResponse($data)); } @@ -669,9 +666,8 @@ public function sendJson(mixed $data): void /** * Sends response and terminates presenter. * @throws Nette\Application\AbortException - * @return never */ - public function sendResponse(Application\Response $response): void + public function sendResponse(Application\Response $response): never { $this->response = $response; $this->terminate(); @@ -681,9 +677,8 @@ public function sendResponse(Application\Response $response): void /** * Correctly terminates presenter. * @throws Nette\Application\AbortException - * @return never */ - public function terminate(): void + public function terminate(): never { throw new Application\AbortException; } @@ -693,9 +688,8 @@ public function terminate(): void * Forward to another presenter or action. * @param array|mixed $args * @throws Nette\Application\AbortException - * @return never */ - public function forward(string|Nette\Application\Request $destination, $args = []): void + public function forward(string|Nette\Application\Request $destination, $args = []): never { if ($destination instanceof Application\Request) { $this->sendResponse(new Responses\ForwardResponse($destination)); @@ -712,9 +706,8 @@ public function forward(string|Nette\Application\Request $destination, $args = [ /** * Redirect to another URL and ends presenter execution. * @throws Nette\Application\AbortException - * @return never */ - public function redirectUrl(string $url, ?int $httpCode = null): void + public function redirectUrl(string $url, ?int $httpCode = null): never { if ($this->isAjax()) { $this->getPayload()->redirect = $url; diff --git a/src/Bridges/ApplicationLatte/TemplateFactory.php b/src/Bridges/ApplicationLatte/TemplateFactory.php index 5ae96343d..31acb518c 100644 --- a/src/Bridges/ApplicationLatte/TemplateFactory.php +++ b/src/Bridges/ApplicationLatte/TemplateFactory.php @@ -37,8 +37,7 @@ public function __construct( } - /** @return Template */ - public function createTemplate(?UI\Control $control = null, ?string $class = null): UI\Template + public function createTemplate(?UI\Control $control = null, ?string $class = null): Template { $class ??= $this->templateClass; if (!is_a($class, Template::class, allow_string: true)) { diff --git a/tests/UI/Component.redirect().phpt b/tests/UI/Component.redirect().phpt index 60f3972f5..2985127c2 100644 --- a/tests/UI/Component.redirect().phpt +++ b/tests/UI/Component.redirect().phpt @@ -24,7 +24,7 @@ class TestPresenter extends Application\UI\Presenter } - public function sendResponse(Application\Response $response): void + public function sendResponse(Application\Response $response): never { parent::sendResponse($this->response = $response); } From dc518bea997fb3d3896ff473961ce7f37d6d0285 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Fri, 15 Oct 2021 18:19:42 +0200 Subject: [PATCH 05/21] RouteList: array access is deprecated --- src/Application/Routers/RouteList.php | 10 ++++++++++ tests/Bridges.DI/RoutingExtension.basic.phpt | 7 ++++--- tests/Routers/RouteList.basic.phpt | 3 +-- tests/Routers/RouteList.modules.phpt | 5 ++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Application/Routers/RouteList.php b/src/Application/Routers/RouteList.php index 126c0d053..1305cc64e 100644 --- a/src/Application/Routers/RouteList.php +++ b/src/Application/Routers/RouteList.php @@ -95,6 +95,13 @@ public function getModule(): ?string */ public function offsetSet($index, $router): void { + if ($router instanceof Route) { + trigger_error('Usage `$router[] = new Route(...)` is deprecated, use `$router->addRoute(...)`.', E_USER_DEPRECATED); + } else { + $class = getclass($router); + trigger_error("Usage `\$router[] = new $class` is deprecated, use `\$router->add(new $class)`.", E_USER_DEPRECATED); + } + if ($index === null) { $this->add($router); } else { @@ -109,6 +116,7 @@ public function offsetSet($index, $router): void */ public function offsetGet($index): Nette\Routing\Router { + trigger_error('Usage `$route = $router[...]` is deprecated, use `$router->getRouters()`.', E_USER_DEPRECATED); if (!$this->offsetExists($index)) { throw new Nette\OutOfRangeException('Offset invalid or out of range'); } @@ -122,6 +130,7 @@ public function offsetGet($index): Nette\Routing\Router */ public function offsetExists($index): bool { + trigger_error('Usage `isset($router[...])` is deprecated.', E_USER_DEPRECATED); return is_int($index) && $index >= 0 && $index < count($this->getRouters()); } @@ -132,6 +141,7 @@ public function offsetExists($index): bool */ public function offsetUnset($index): void { + trigger_error('Usage `unset($router[$index])` is deprecated, use `$router->modify($index, null)`.', E_USER_DEPRECATED); if (!$this->offsetExists($index)) { throw new Nette\OutOfRangeException('Offset invalid or out of range'); } diff --git a/tests/Bridges.DI/RoutingExtension.basic.phpt b/tests/Bridges.DI/RoutingExtension.basic.phpt index a8e13d1a6..0b6f57a72 100644 --- a/tests/Bridges.DI/RoutingExtension.basic.phpt +++ b/tests/Bridges.DI/RoutingExtension.basic.phpt @@ -31,9 +31,10 @@ test('', function () { $container = new Container1; $router = $container->getService('router'); Assert::type(Nette\Application\Routers\RouteList::class, $router); - Assert::same('index.php', $router[0]->getMask()); - Assert::same('item/', $router[1]->getMask()); + $routes = $router->getRouters(); + Assert::same('index.php', $routes[0]->getMask()); + Assert::same('item/', $routes[1]->getMask()); Assert::type(Nette\Application\Routers\RouteList::class, $router); - Assert::type(Nette\Application\Routers\Route::class, $router[0]); + Assert::type(Nette\Application\Routers\Route::class, $routes[0]); }); diff --git a/tests/Routers/RouteList.basic.phpt b/tests/Routers/RouteList.basic.phpt index 22afeda6c..b4783db95 100644 --- a/tests/Routers/RouteList.basic.phpt +++ b/tests/Routers/RouteList.basic.phpt @@ -6,7 +6,6 @@ declare(strict_types=1); -use Nette\Application\Routers\Route; use Nette\Application\Routers\RouteList; use Tester\Assert; @@ -17,7 +16,7 @@ require __DIR__ . '/Route.php'; $list = new RouteList; -$list[] = new Route('//'); +$list->addRoute('//'); Assert::same('http://example.com/front.homepage/', testRouteOut($list, ['presenter' => 'Front:Homepage'])); diff --git a/tests/Routers/RouteList.modules.phpt b/tests/Routers/RouteList.modules.phpt index db2aff0d2..ff1e15193 100644 --- a/tests/Routers/RouteList.modules.phpt +++ b/tests/Routers/RouteList.modules.phpt @@ -6,7 +6,6 @@ declare(strict_types=1); -use Nette\Application\Routers\Route; use Nette\Application\Routers\RouteList; @@ -16,12 +15,12 @@ require __DIR__ . '/Route.php'; $list = new RouteList; -$list[] = new Route('auth/[/]', [ +$list->addRoute('auth/[/]', [ 'module' => 'Auth', 'presenter' => 'Homepage', 'action' => 'default', ]); -$list[] = new Route('[/]', [ +$list->addRoute('[/]', [ 'module' => 'Default', 'presenter' => 'Homepage', 'action' => 'default', From 819557947cad68fbe904b08bbce26be0df907345 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 12 May 2024 20:35:11 +0200 Subject: [PATCH 06/21] Presenter::handleInvalidLink() -> processInvalidLink() (BC break) --- src/Application/UI/Component.php | 2 +- src/Application/UI/Presenter.php | 2 +- src/Bridges/ApplicationDI/ApplicationExtension.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Application/UI/Component.php b/src/Application/UI/Component.php index aa469e551..03247eedd 100644 --- a/src/Application/UI/Component.php +++ b/src/Application/UI/Component.php @@ -293,7 +293,7 @@ public function link(string $destination, $args = []): string return $this->getPresenter()->getLinkGenerator()->link($destination, $args, $this, 'link'); } catch (InvalidLinkException $e) { - return $this->getPresenter()->handleInvalidLink($e); + return $this->getPresenter()->processInvalidLink($e); } } diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index b3dd9cda0..70c5569c5 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -827,7 +827,7 @@ protected function requestToUrl(Application\Request $request, ?bool $relative = * Invalid link handler. Descendant can override this method to change default behaviour. * @throws InvalidLinkException */ - protected function handleInvalidLink(InvalidLinkException $e): string + protected function processInvalidLink(InvalidLinkException $e): string { if ($this->invalidLinkMode & self::InvalidLinkException) { throw $e; diff --git a/src/Bridges/ApplicationDI/ApplicationExtension.php b/src/Bridges/ApplicationDI/ApplicationExtension.php index 5acd5bf97..e93f95ef4 100644 --- a/src/Bridges/ApplicationDI/ApplicationExtension.php +++ b/src/Bridges/ApplicationDI/ApplicationExtension.php @@ -275,7 +275,7 @@ private function checkPresenter(string $class): void $re = $class::formatActionMethod('') . '.|' . $class::formatRenderMethod('') . '.|' . $class::formatSignalMethod('') . '.'; foreach ($rc->getMethods() as $rm) { - if (preg_match("#^(?!handleInvalidLink)($re)#", $rm->getName()) && (!$rm->isPublic() || $rm->isStatic())) { + if (preg_match("#^$re#", $rm->getName()) && (!$rm->isPublic() || $rm->isStatic())) { throw new Nette\InvalidStateException(sprintf('Method %s: this method must be public non-static.', Reflection::toString($rm))); } elseif (preg_match('#^createComponent.#', $rm->getName()) && ($rm->isPrivate() || $rm->isStatic())) { throw new Nette\InvalidStateException(sprintf('Method %s: this method must be non-private non-static.', Reflection::toString($rm))); From a43dc48956e6c4e0149ae4819fcc15289a3295f7 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 24 Oct 2022 19:12:55 +0200 Subject: [PATCH 07/21] Revert "UI\PresenterComponent: removed references created by loadState() for persistent parameters. [Closes nette/nette#703][Closes nette/nette#703][Closes #69]" (possible BC break) This reverts commit cda17f460d020b0f042364d4e140742022a7e94d. See https://forum.nette.org/cs/35528-stejne-pojmenovany-parametr-akce-presenteru-a-persistentni-odlisne-chovani-v-nette-2-0-oproti-aktualnimu#p221742 BC break: Property must be nullable, ie: #[Persistent] public ?int $foo --- src/Application/UI/Component.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Application/UI/Component.php b/src/Application/UI/Component.php index 03247eedd..5614e3f54 100644 --- a/src/Application/UI/Component.php +++ b/src/Application/UI/Component.php @@ -161,9 +161,9 @@ public function loadState(array $params): void )); } - $this->$name = $params[$name]; + $this->$name = &$params[$name]; } else { - $params[$name] = $this->$name ?? null; + $params[$name] = &$this->$name; } } @@ -236,7 +236,7 @@ final public function getParameter(string $name): mixed */ final public function getParameters(): array { - return $this->params; + return array_map(fn($item) => $item, $this->params); } From 6df3a08fa94ad176cbdf56e7bcfd2c41b597a567 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sat, 20 Apr 2024 02:43:19 +0200 Subject: [PATCH 08/21] Component: method checkRequirements() is called for createComponent() methods (BC break) --- src/Application/UI/Component.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Application/UI/Component.php b/src/Application/UI/Component.php index 5614e3f54..7c3ef4f16 100644 --- a/src/Application/UI/Component.php +++ b/src/Application/UI/Component.php @@ -74,7 +74,8 @@ public function getUniqueId(): string protected function createComponent(string $name): ?Nette\ComponentModel\IComponent { if (method_exists($this, $method = 'createComponent' . $name)) { - (new AccessPolicy($this, new \ReflectionMethod($this, $method)))->checkAccess(); + (new AccessPolicy($this, $rm = new \ReflectionMethod($this, $method)))->checkAccess(); + $this->checkRequirements($rm); } $res = parent::createComponent($name); if ($res && !$res instanceof SignalReceiver && !$res instanceof StatePersistent) { From a061fe16e681bd8b0b90ee08b3ad48d58d02b67e Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 7 Apr 2024 04:33:34 +0200 Subject: [PATCH 09/21] Component: only UI components can be added to presenter/component (BC break) WIP --- src/Application/UI/Component.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Application/UI/Component.php b/src/Application/UI/Component.php index 7c3ef4f16..833b8d56f 100644 --- a/src/Application/UI/Component.php +++ b/src/Application/UI/Component.php @@ -71,19 +71,27 @@ public function getUniqueId(): string } + public function addComponent( + Nette\ComponentModel\IComponent $component, + ?string $name, + ?string $insertBefore = null, + ): static + { + if (!$component instanceof SignalReceiver && !$component instanceof StatePersistent) { + throw new Nette\InvalidStateException("Component '$name' of type " . get_debug_type($component) . ' is not intended to be used in the Presenter.'); + } + + return parent::addComponent($component, $name, $insertBefore = null); + } + + protected function createComponent(string $name): ?Nette\ComponentModel\IComponent { if (method_exists($this, $method = 'createComponent' . $name)) { (new AccessPolicy($this, $rm = new \ReflectionMethod($this, $method)))->checkAccess(); $this->checkRequirements($rm); } - $res = parent::createComponent($name); - if ($res && !$res instanceof SignalReceiver && !$res instanceof StatePersistent) { - $type = $res::class; - trigger_error("It seems that component '$name' of type $type is not intended to be used in the Presenter."); - } - - return $res; + return parent::createComponent($name); } From 31a1179a23cd88634d7fa967f663cbd267bf712d Mon Sep 17 00:00:00 2001 From: David Grudl Date: Fri, 24 Sep 2021 14:06:27 +0200 Subject: [PATCH 10/21] deprecated magic properties except for $template & $payload (BC break) --- src/Application/Request.php | 10 +++++----- src/Application/UI/Component.php | 4 ++-- src/Application/UI/ComponentReflection.php | 4 ++-- src/Application/UI/Presenter.php | 12 ++++++------ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Application/Request.php b/src/Application/Request.php index 5c9985ce3..10b5f2782 100644 --- a/src/Application/Request.php +++ b/src/Application/Request.php @@ -15,11 +15,11 @@ /** * Presenter request. * - * @property string $presenterName - * @property array $parameters - * @property array $post - * @property array $files - * @property string|null $method + * @property-deprecated string $presenterName + * @property-deprecated array $parameters + * @property-deprecated array $post + * @property-deprecated array $files + * @property-deprecated string|null $method */ final class Request { diff --git a/src/Application/UI/Component.php b/src/Application/UI/Component.php index 833b8d56f..8e97bb2d2 100644 --- a/src/Application/UI/Component.php +++ b/src/Application/UI/Component.php @@ -19,8 +19,8 @@ * other child components, and interact with user. Components have properties * for storing their status, and responds to user command. * - * @property-read Presenter $presenter - * @property-read bool $linkCurrent + * @property-deprecated Presenter $presenter + * @property-deprecated bool $linkCurrent */ abstract class Component extends Nette\ComponentModel\Container implements SignalReceiver, StatePersistent, \ArrayAccess { diff --git a/src/Application/UI/ComponentReflection.php b/src/Application/UI/ComponentReflection.php index 4f9cbbbf6..bfce01768 100644 --- a/src/Application/UI/ComponentReflection.php +++ b/src/Application/UI/ComponentReflection.php @@ -15,8 +15,8 @@ /** * Helpers for Presenter & Component. - * @property-read string $name - * @property-read string $fileName + * @property-deprecated string $name + * @property-deprecated string $fileName * @internal */ final class ComponentReflection extends \ReflectionClass diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index 70c5569c5..1abc8ce64 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -21,13 +21,13 @@ /** * Presenter component represents a webpage instance. It converts Request to Response. * - * @property-read Nette\Application\Request $request - * @property-read string $action - * @property string $view - * @property string|bool $layout + * @property-deprecated Nette\Application\Request $request + * @property-deprecated string $action + * @property-deprecated string $view + * @property-deprecated string|bool $layout * @property-read \stdClass $payload - * @property-read Nette\Http\Session $session - * @property-read Nette\Security\User $user + * @property-deprecated Nette\Http\Session $session + * @property-deprecated Nette\Security\User $user */ abstract class Presenter extends Control implements Application\IPresenter { From 13a461628415f4623268f342b94189f30c4b894e Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 20 Oct 2021 01:53:14 +0200 Subject: [PATCH 11/21] Component::link() & etc uses variadic parameter --- src/Application/UI/Component.php | 50 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Application/UI/Component.php b/src/Application/UI/Component.php index 8e97bb2d2..3218a9b95 100644 --- a/src/Application/UI/Component.php +++ b/src/Application/UI/Component.php @@ -290,15 +290,15 @@ public static function formatSignalMethod(string $signal): string /** * Generates URL to presenter, action or signal. * @param string $destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" - * @param array|mixed $args + * @param mixed ...$args * @throws InvalidLinkException */ - public function link(string $destination, $args = []): string + public function link(string $destination, ...$args): string { try { - $args = func_num_args() < 3 && is_array($args) - ? $args - : array_slice(func_get_args(), 1); + $args = count($args) === 1 && is_array($args[0] ?? null) + ? $args[0] + : $args; return $this->getPresenter()->getLinkGenerator()->link($destination, $args, $this, 'link'); } catch (InvalidLinkException $e) { @@ -310,13 +310,13 @@ public function link(string $destination, $args = []): string /** * Returns destination as Link object. * @param string $destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" - * @param array|mixed $args + * @param mixed ...$args */ - public function lazyLink(string $destination, $args = []): Link + public function lazyLink(string $destination, ...$args): Link { - $args = func_num_args() < 3 && is_array($args) - ? $args - : array_slice(func_get_args(), 1); + $args = count($args) === 1 && is_array($args[0] ?? null) + ? $args[0] + : $args; return new Link($this, $destination, $args); } @@ -324,15 +324,15 @@ public function lazyLink(string $destination, $args = []): Link /** * Determines whether it links to the current page. * @param ?string $destination in format "[[[module:]presenter:]action | signal! | this]" - * @param array|mixed $args + * @param mixed ...$args * @throws InvalidLinkException */ - public function isLinkCurrent(?string $destination = null, $args = []): bool + public function isLinkCurrent(?string $destination = null, ...$args): bool { if ($destination !== null) { - $args = func_num_args() < 3 && is_array($args) - ? $args - : array_slice(func_get_args(), 1); + $args = count($args) === 1 && is_array($args[0] ?? null) + ? $args[0] + : $args; $this->getPresenter()->getLinkGenerator()->createRequest($this, $destination, $args, 'test'); } @@ -343,14 +343,14 @@ public function isLinkCurrent(?string $destination = null, $args = []): bool /** * Redirect to another presenter, action or signal. * @param string $destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" - * @param array|mixed $args + * @param mixed ...$args * @throws Nette\Application\AbortException */ - public function redirect(string $destination, $args = []): never + public function redirect(string $destination, ...$args): never { - $args = func_num_args() < 3 && is_array($args) - ? $args - : array_slice(func_get_args(), 1); + $args = count($args) === 1 && is_array($args[0] ?? null) + ? $args[0] + : $args; $presenter = $this->getPresenter(); $presenter->saveGlobalState(); $presenter->redirectUrl($presenter->getLinkGenerator()->link($destination, $args, $this, 'redirect')); @@ -360,14 +360,14 @@ public function redirect(string $destination, $args = []): never /** * Permanently redirects to presenter, action or signal. * @param string $destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" - * @param array|mixed $args + * @param mixed ...$args * @throws Nette\Application\AbortException */ - public function redirectPermanent(string $destination, $args = []): never + public function redirectPermanent(string $destination, ...$args): never { - $args = func_num_args() < 3 && is_array($args) - ? $args - : array_slice(func_get_args(), 1); + $args = count($args) === 1 && is_array($args[0] ?? null) + ? $args[0] + : $args; $presenter = $this->getPresenter(); $presenter->redirectUrl( $presenter->getLinkGenerator()->link($destination, $args, $this, 'redirect'), From 52410d9051cac35abbcbf370a5d4a1be1455bb98 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 21 Jun 2022 15:27:13 +0200 Subject: [PATCH 12/21] Component::getParameter() $default is deprecated --- src/Application/UI/Component.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Application/UI/Component.php b/src/Application/UI/Component.php index 3218a9b95..682eb7e56 100644 --- a/src/Application/UI/Component.php +++ b/src/Application/UI/Component.php @@ -234,6 +234,7 @@ public function saveStatePartial(array &$params, ComponentReflection $reflection final public function getParameter(string $name): mixed { if (func_num_args() > 1) { + trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', E_USER_DEPRECATED); $default = func_get_arg(1); } return $this->params[$name] ?? $default ?? null; From d3a858cdd3b782dc450a6294710f73811def7a05 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 28 Apr 2024 14:29:04 +0200 Subject: [PATCH 13/21] PresenterFactoryCallback: refreshes page instead of creating presenters dynamically [WIP] does not work when scanDirs is disabled --- .../ApplicationDI/ApplicationExtension.php | 2 +- .../PresenterFactoryCallback.php | 23 ++++--------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/Bridges/ApplicationDI/ApplicationExtension.php b/src/Bridges/ApplicationDI/ApplicationExtension.php index e93f95ef4..a08080fe0 100644 --- a/src/Bridges/ApplicationDI/ApplicationExtension.php +++ b/src/Bridges/ApplicationDI/ApplicationExtension.php @@ -96,7 +96,7 @@ public function loadConfiguration(): void ->setType(Nette\Application\IPresenterFactory::class) ->setFactory(Nette\Application\PresenterFactory::class, [new Definitions\Statement( Nette\Bridges\ApplicationDI\PresenterFactoryCallback::class, - [1 => $this->invalidLinkMode, $touch ?? null], + [1 => $touch ?? null], )]); if ($config->mapping) { diff --git a/src/Bridges/ApplicationDI/PresenterFactoryCallback.php b/src/Bridges/ApplicationDI/PresenterFactoryCallback.php index 7e60db7c0..dcca2eea0 100644 --- a/src/Bridges/ApplicationDI/PresenterFactoryCallback.php +++ b/src/Bridges/ApplicationDI/PresenterFactoryCallback.php @@ -20,7 +20,6 @@ final class PresenterFactoryCallback { public function __construct( private readonly Nette\DI\Container $container, - private readonly int $invalidLinkMode, private readonly ?string $touchToRefresh, ) { } @@ -40,25 +39,13 @@ public function __invoke(string $class): Nette\Application\IPresenter return $this->container->createService($services[0]); } - if ($this->touchToRefresh) { + if ($this->touchToRefresh && class_exists($class)) { touch($this->touchToRefresh); + header('Refresh: 3'); + echo "The DI container does not know the $class class. I will refresh it in 3 seconds."; + exit; } - try { - $presenter = $this->container->createInstance($class); - $this->container->callInjects($presenter); - } catch (Nette\DI\MissingServiceException | Nette\DI\ServiceCreationException $e) { - if ($this->touchToRefresh && class_exists($class)) { - throw new \Exception("Refresh your browser. New presenter $class was found.", 0, $e); - } - - throw $e; - } - - if ($presenter instanceof Nette\Application\UI\Presenter && !isset($presenter->invalidLinkMode)) { - $presenter->invalidLinkMode = $this->invalidLinkMode; - } - - return $presenter; + throw new Nette\Application\InvalidPresenterException("No services of type $class found."); } } From 7da2e5758010a7002fe61da9d9085b0b4dcccd96 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Fri, 19 Apr 2024 19:20:51 +0200 Subject: [PATCH 14/21] LinkGenerator: query part in link is deprecated --- src/Application/LinkGenerator.php | 1 + tests/UI/LinkGenerator.parseDestination().phpt | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Application/LinkGenerator.php b/src/Application/LinkGenerator.php index ad2a70e7a..ce99f23ce 100644 --- a/src/Application/LinkGenerator.php +++ b/src/Application/LinkGenerator.php @@ -242,6 +242,7 @@ public static function parseDestination(string $destination): array } if (!empty($matches['query'])) { + trigger_error("Link format is obsolete, use arguments instead of query string in '$destination'.", E_USER_DEPRECATED); parse_str(substr($matches['query'], 1), $args); } diff --git a/tests/UI/LinkGenerator.parseDestination().phpt b/tests/UI/LinkGenerator.parseDestination().phpt index 5132e99a4..82655a85b 100644 --- a/tests/UI/LinkGenerator.parseDestination().phpt +++ b/tests/UI/LinkGenerator.parseDestination().phpt @@ -48,7 +48,7 @@ Assert::same([ 'signal' => false, 'args' => [], 'fragment' => '#fragment', -], LinkGenerator::parseDestination('a:b?#fragment')); +], @LinkGenerator::parseDestination('a:b?#fragment')); // deprecated Assert::same([ 'absolute' => false, @@ -56,7 +56,7 @@ Assert::same([ 'signal' => false, 'args' => ['a' => 'b', 'c' => 'd'], 'fragment' => '#fragment', -], LinkGenerator::parseDestination('a:b?a=b&c=d#fragment')); +], @LinkGenerator::parseDestination('a:b?a=b&c=d#fragment')); // deprecated Assert::exception( fn() => LinkGenerator::parseDestination(''), From 95fa3e2e6d96c8f23d66ec466b6a24976344ab8a Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 12 Dec 2023 00:11:10 +0100 Subject: [PATCH 15/21] Presenter: removed constructor (BC break!) --- src/Application/UI/Presenter.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index 1abc8ce64..82bf72c92 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -114,11 +114,6 @@ abstract class Presenter extends Control implements Application\IPresenter private readonly LinkGenerator $linkGenerator; - public function __construct() - { - } - - final public function getRequest(): ?Application\Request { return $this->request; From c4767bb65ec2c187d5cb4cb4d6179935e3a4b956 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Fri, 19 Apr 2024 18:59:59 +0200 Subject: [PATCH 16/21] @annotations are deprecated (BC break) --- src/Application/UI/ComponentReflection.php | 14 +++++++++-- src/Application/UI/MethodReflection.php | 4 ++++ .../ComponentReflection.getParameters().phpt | 2 +- ...tReflection.getPersistentComponents().phpt | 13 ----------- .../ComponentReflection.parseAnnotation.phpt | 16 ++++++------- tests/UI/Presenter.link().persistent.phpt | 17 +++++++------- tests/UI/Presenter.link().phpt | 23 ++++++++++--------- tests/UI/fixtures/ParamPresenter.php | 2 +- 8 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/Application/UI/ComponentReflection.php b/src/Application/UI/ComponentReflection.php index bfce01768..b04b84f03 100644 --- a/src/Application/UI/ComponentReflection.php +++ b/src/Application/UI/ComponentReflection.php @@ -27,7 +27,7 @@ final class ComponentReflection extends \ReflectionClass /** - * Returns array of class properties that are public and have attribute #[Persistent] or #[Parameter] or annotation @persistent. + * Returns array of class properties that are public and have attribute #[Persistent] or #[Parameter]. * @return array */ public function getParameters(): array @@ -74,7 +74,7 @@ public function getParameters(): array /** - * Returns array of persistent properties. They are public and have attribute #[Persistent] or annotation @persistent. + * Returns array of persistent properties. They are public and have attribute #[Persistent]. * @return array */ public function getPersistentParams(): array @@ -149,6 +149,7 @@ public function getSignalMethod(string $signal): ?\ReflectionMethod /** * Returns an annotation value. + * @deprecated */ public static function parseAnnotation(\Reflector $ref, string $name): ?array { @@ -166,12 +167,20 @@ public static function parseAnnotation(\Reflector $ref, string $name): ?array } } + $alt = match ($name) { + 'persistent' => '#[Nette\Application\Attributes\Persistent]', + 'deprecated' => '#[Nette\Application\Attributes\Deprecated]', + 'crossOrigin' => '#[Nette\Application\Attributes\Request(sameOrigin: false)]', + default => 'alternative' + }; + trigger_error("Annotation @$name is deprecated, use $alt (used in " . Nette\Utils\Reflection::toString($ref) . ')', E_USER_DEPRECATED); return $res; } /** * Has class specified annotation? + * @deprecated */ public function hasAnnotation(string $name): bool { @@ -181,6 +190,7 @@ public function hasAnnotation(string $name): bool /** * Returns an annotation value. + * @deprecated */ public function getAnnotation(string $name): mixed { diff --git a/src/Application/UI/MethodReflection.php b/src/Application/UI/MethodReflection.php index f576deeaf..f84687356 100644 --- a/src/Application/UI/MethodReflection.php +++ b/src/Application/UI/MethodReflection.php @@ -17,18 +17,22 @@ final class MethodReflection extends \ReflectionMethod { /** * Has method specified annotation? + * @deprecated */ public function hasAnnotation(string $name): bool { + trigger_error(__METHOD__ . '() is deprecated', E_USER_DEPRECATED); return (bool) ComponentReflection::parseAnnotation($this, $name); } /** * Returns an annotation value. + * @deprecated */ public function getAnnotation(string $name): mixed { + trigger_error(__METHOD__ . '() is deprecated', E_USER_DEPRECATED); $res = ComponentReflection::parseAnnotation($this, $name); return $res ? end($res) : null; } diff --git a/tests/UI/ComponentReflection.getParameters().phpt b/tests/UI/ComponentReflection.getParameters().phpt index e1d177edc..dd0154b59 100644 --- a/tests/UI/ComponentReflection.getParameters().phpt +++ b/tests/UI/ComponentReflection.getParameters().phpt @@ -16,7 +16,7 @@ class OnePresenter extends Presenter public static $no1; public $no2; - /** @persistent */ + #[Persistent] public $yes1; #[Persistent, Parameter] diff --git a/tests/UI/ComponentReflection.getPersistentComponents().phpt b/tests/UI/ComponentReflection.getPersistentComponents().phpt index 2654e06d9..febe683f3 100644 --- a/tests/UI/ComponentReflection.getPersistentComponents().phpt +++ b/tests/UI/ComponentReflection.getPersistentComponents().phpt @@ -14,14 +14,6 @@ class NonePresenter extends Presenter } -/** - * @persistent(a, b) - */ -class AnnotationPresenter extends Presenter -{ -} - - #[Persistent('a', 'b')] class AttributePresenter extends Presenter { @@ -39,11 +31,6 @@ class MethodPresenter extends AttributePresenter Assert::same([], NonePresenter::getReflection()->getPersistentComponents()); -Assert::same([ - 'a' => ['since' => AnnotationPresenter::class], - 'b' => ['since' => AnnotationPresenter::class], -], AnnotationPresenter::getReflection()->getPersistentComponents()); - Assert::same([ 'a' => ['since' => AttributePresenter::class], 'b' => ['since' => AttributePresenter::class], diff --git a/tests/UI/ComponentReflection.parseAnnotation.phpt b/tests/UI/ComponentReflection.parseAnnotation.phpt index 278b5e7d1..71a614e90 100644 --- a/tests/UI/ComponentReflection.parseAnnotation.phpt +++ b/tests/UI/ComponentReflection.parseAnnotation.phpt @@ -34,11 +34,11 @@ class TestClass $rc = new ReflectionClass('TestClass'); -Assert::same(['value ="Johno\'s addendum"', 'mode=True', true, true], Reflection::parseAnnotation($rc, 'title')); -Assert::null(Reflection::parseAnnotation($rc, 'public')); -Assert::null(Reflection::parseAnnotation($rc, 'private')); -Assert::same(['item 1'], Reflection::parseAnnotation($rc, 'components')); -Assert::same([true, false, null], Reflection::parseAnnotation($rc, 'persistent')); -Assert::same([true], Reflection::parseAnnotation($rc, 'renderable')); -Assert::same(['loggedIn'], Reflection::parseAnnotation($rc, 'Secured\User')); -Assert::null(Reflection::parseAnnotation($rc, 'missing')); +Assert::same(['value ="Johno\'s addendum"', 'mode=True', true, true], @Reflection::parseAnnotation($rc, 'title')); +Assert::null(@Reflection::parseAnnotation($rc, 'public')); +Assert::null(@Reflection::parseAnnotation($rc, 'private')); +Assert::same(['item 1'], @Reflection::parseAnnotation($rc, 'components')); +Assert::same([true, false, null], @Reflection::parseAnnotation($rc, 'persistent')); +Assert::same([true], @Reflection::parseAnnotation($rc, 'renderable')); +Assert::same(['loggedIn'], @Reflection::parseAnnotation($rc, 'Secured\User')); +Assert::null(@Reflection::parseAnnotation($rc, 'missing')); diff --git a/tests/UI/Presenter.link().persistent.phpt b/tests/UI/Presenter.link().persistent.phpt index 8866f892c..e26932c76 100644 --- a/tests/UI/Presenter.link().persistent.phpt +++ b/tests/UI/Presenter.link().persistent.phpt @@ -7,6 +7,7 @@ declare(strict_types=1); use Nette\Application; +use Nette\Application\Attributes\Persistent; use Nette\Http; use Tester\Assert; @@ -16,13 +17,13 @@ require __DIR__ . '/../bootstrap.php'; trait PersistentParam1 { - /** @persistent */ + #[Persistent] public $t1; } trait PersistentParam2A { - /** @persistent */ + #[Persistent] public $t2; } @@ -33,7 +34,7 @@ trait PersistentParam2B trait PersistentParam3 { - /** @persistent */ + #[Persistent] public $t3; } @@ -41,7 +42,7 @@ class BasePresenter extends Application\UI\Presenter { use PersistentParam1; - /** @persistent */ + #[Persistent] public $p1; } @@ -50,7 +51,7 @@ class TestPresenter extends BasePresenter { use PersistentParam2B; - /** @persistent */ + #[Persistent] public $p2; @@ -81,10 +82,10 @@ class SecondPresenter extends BasePresenter { use PersistentParam3; - /** @persistent */ + #[Persistent] public $p1 = 20; - /** @persistent */ + #[Persistent] public $p3; } @@ -97,7 +98,7 @@ class ThirdPresenter extends BasePresenter class FourthPresenter extends BasePresenter { - #[Application\Attributes\Persistent] + #[Persistent] public $p1; } diff --git a/tests/UI/Presenter.link().phpt b/tests/UI/Presenter.link().phpt index b6b129d28..cfdf59d09 100644 --- a/tests/UI/Presenter.link().phpt +++ b/tests/UI/Presenter.link().phpt @@ -7,6 +7,7 @@ declare(strict_types=1); use Nette\Application; +use Nette\Application\Attributes\Persistent; use Nette\Http; use Tester\Assert; @@ -16,11 +17,11 @@ require __DIR__ . '/../bootstrap.php'; class TestControl extends Application\UI\Control { - /** @persistent array */ - public $order = []; + #[Persistent] + public array $order = []; - /** @persistent int */ - public $round = 0; + #[Persistent] + public int $round = 0; public function handleClick($x, $y) @@ -50,22 +51,22 @@ class TestControl extends Application\UI\Control class TestPresenter extends Application\UI\Presenter { - /** @persistent */ + #[Persistent] public $p; - /** @persistent */ + #[Persistent] public $pint = 10; - /** @persistent */ + #[Persistent] public $parr = []; - /** @persistent */ + #[Persistent] public $pbool = true; - /** @persistent */ + #[Persistent] public array $parrn; - /** @persistent */ + #[Persistent] public ?bool $pbooln = null; @@ -294,7 +295,7 @@ class TestPresenter extends Application\UI\Presenter class OtherPresenter extends TestPresenter { - /** @persistent */ + #[Persistent] public $p = 20; } diff --git a/tests/UI/fixtures/ParamPresenter.php b/tests/UI/fixtures/ParamPresenter.php index 453a78c34..21e04cca4 100644 --- a/tests/UI/fixtures/ParamPresenter.php +++ b/tests/UI/fixtures/ParamPresenter.php @@ -4,7 +4,7 @@ class ParamPresenter extends Nette\Application\UI\Presenter { - /** @persistent */ + #[Nette\Application\Attributes\Persistent] public $bool = true; From 6ef6c904864f8c47b74c71975d2f1e496e07be60 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sat, 6 Apr 2024 18:44:44 +0200 Subject: [PATCH 17/21] LatteFactory: $control is passed to create() (BC break) --- src/Bridges/ApplicationDI/LatteExtension.php | 5 +++-- src/Bridges/ApplicationLatte/LatteFactory.php | 3 ++- src/Bridges/ApplicationLatte/TemplateFactory.php | 4 ---- tests/Bridges.DI/LatteExtension.basic.phpt | 14 -------------- 4 files changed, 5 insertions(+), 21 deletions(-) diff --git a/src/Bridges/ApplicationDI/LatteExtension.php b/src/Bridges/ApplicationDI/LatteExtension.php index 5a9cb0858..f26c5d393 100644 --- a/src/Bridges/ApplicationDI/LatteExtension.php +++ b/src/Bridges/ApplicationDI/LatteExtension.php @@ -59,8 +59,9 @@ public function loadConfiguration(): void ->addSetup('setAutoRefresh', [$this->debugMode]) ->addSetup('setStrictTypes', [$config->strictTypes]) ->addSetup('setStrictParsing', [$config->strictParsing]) - ->addSetup('enablePhpLinter', [$config->phpLinter]) - ->addSetup('?', [$builder::literal('func_num_args() && $service->addExtension(new Nette\Bridges\ApplicationLatte\UIExtension(func_get_arg(0)))')]); + ->addSetup('enablePhpLinter', [$config->phpLinter]); + + $this->addExtension(new Statement(ApplicationLatte\UIExtension::class, [$builder::literal('$control')])); if ($builder->getByType(Nette\Caching\Storage::class)) { $this->addExtension(new Statement(Nette\Bridges\CacheLatte\CacheExtension::class)); diff --git a/src/Bridges/ApplicationLatte/LatteFactory.php b/src/Bridges/ApplicationLatte/LatteFactory.php index e6d2c8842..71e1ced0c 100644 --- a/src/Bridges/ApplicationLatte/LatteFactory.php +++ b/src/Bridges/ApplicationLatte/LatteFactory.php @@ -10,11 +10,12 @@ namespace Nette\Bridges\ApplicationLatte; use Latte; +use Nette\Application\UI\Control; interface LatteFactory { - function create(/*?Control $control = null*/): Latte\Engine; + function create(?Control $control = null): Latte\Engine; } diff --git a/src/Bridges/ApplicationLatte/TemplateFactory.php b/src/Bridges/ApplicationLatte/TemplateFactory.php index 31acb518c..1f2cbb764 100644 --- a/src/Bridges/ApplicationLatte/TemplateFactory.php +++ b/src/Bridges/ApplicationLatte/TemplateFactory.php @@ -48,10 +48,6 @@ public function createTemplate(?UI\Control $control = null, ?string $class = nul $template = new $class($latte); $presenter = $control?->getPresenterIfExists(); - if (!Nette\Utils\Arrays::some($latte->getExtensions(), fn($e) => $e instanceof UIExtension)) { - $latte->addExtension(new UIExtension($control)); - } - // default parameters $baseUrl = $this->httpRequest ? rtrim($this->httpRequest->getUrl()->withoutUserInfo()->getBaseUrl(), '/') diff --git a/tests/Bridges.DI/LatteExtension.basic.phpt b/tests/Bridges.DI/LatteExtension.basic.phpt index 34ea641d5..a3a13d48f 100644 --- a/tests/Bridges.DI/LatteExtension.basic.phpt +++ b/tests/Bridges.DI/LatteExtension.basic.phpt @@ -59,20 +59,6 @@ Assert::type(Nette\Bridges\ApplicationLatte\LatteFactory::class, $container->get $latte = $container->getService('nette.latteFactory')->create(); $extensions = Assert::with($latte, fn() => $this->extensions); -Assert::equal([ - new Latte\Essential\CoreExtension, - new Latte\Sandbox\SandboxExtension, - new Nette\Bridges\FormsLatte\FormsExtension, - new MyExtension, - new MyExtension(1), - new MyExtension(2), - new MyExtension, -], $extensions); - -// UIExtension is added -$latte = $container->getService('nette.latteFactory')->create(null); -$extensions = Assert::with($latte, fn() => $this->extensions); - Assert::equal([ new Latte\Essential\CoreExtension, new Latte\Sandbox\SandboxExtension, From 8b57c9fe9e686ac3733649a02656f9e523e108ea Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 15 Apr 2024 01:38:08 +0200 Subject: [PATCH 18/21] PresenterFactory: default mapping is App\UI\*\**Presenter (BC break) --- src/Application/PresenterFactory.php | 2 +- .../PresenterFactory.formatPresenterClass.phpt | 18 +++++++++--------- tests/Routers/LinkGenerator.phpt | 8 +++++--- tests/Routers/link-aliases.phpt | 1 + 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/Application/PresenterFactory.php b/src/Application/PresenterFactory.php index 225f04768..af7203fdf 100644 --- a/src/Application/PresenterFactory.php +++ b/src/Application/PresenterFactory.php @@ -19,7 +19,7 @@ class PresenterFactory implements IPresenterFactory { /** @var array[] of module => splited mask */ private array $mapping = [ - '*' => ['', '*Module\\', '*Presenter'], + '*' => ['App\\UI\\', '*\\', '**Presenter'], 'Nette' => ['NetteModule\\', '*\\', '*Presenter'], ]; diff --git a/tests/Application/PresenterFactory.formatPresenterClass.phpt b/tests/Application/PresenterFactory.formatPresenterClass.phpt index 3ef876bb9..1c3073a29 100644 --- a/tests/Application/PresenterFactory.formatPresenterClass.phpt +++ b/tests/Application/PresenterFactory.formatPresenterClass.phpt @@ -21,11 +21,11 @@ test('defined module', function () { 'Foo3' => 'My\App\*Mod\*Presenter', ]); - Assert::same('FooPresenter', $factory->formatPresenterClass('Foo')); - Assert::same('FooModule\BarPresenter', $factory->formatPresenterClass('Foo:Bar')); - Assert::same('FooModule\BarModule\BazPresenter', $factory->formatPresenterClass('Foo:Bar:Baz')); + Assert::same('App\UI\Foo\FooPresenter', $factory->formatPresenterClass('Foo')); + Assert::same('App\UI\Foo\Bar\BarPresenter', $factory->formatPresenterClass('Foo:Bar')); + Assert::same('App\UI\Foo\Bar\Baz\BazPresenter', $factory->formatPresenterClass('Foo:Bar:Baz')); - Assert::same('Foo2Presenter', $factory->formatPresenterClass('Foo2')); + Assert::same('App\UI\Foo2\Foo2Presenter', $factory->formatPresenterClass('Foo2')); Assert::same('App2\BarPresenter', $factory->formatPresenterClass('Foo2:Bar')); Assert::same('App2\Bar\BazPresenter', $factory->formatPresenterClass('Foo2:Bar:Baz')); @@ -44,7 +44,7 @@ test('auto module', function () { 'Foo3' => 'My\App\*Presenter', ]); - Assert::same('Foo2Presenter', $factory->formatPresenterClass('Foo2')); + Assert::same('App\UI\Foo2\Foo2Presenter', $factory->formatPresenterClass('Foo2')); Assert::same('App2\BarPresenter', $factory->formatPresenterClass('Foo2:Bar')); Assert::same('App2\BarModule\BazPresenter', $factory->formatPresenterClass('Foo2:Bar:Baz')); @@ -61,11 +61,11 @@ test('location ** & defined module', function () { 'Foo3' => 'My\App\*Mod\**Presenter', ]); - Assert::same('FooPresenter', $factory->formatPresenterClass('Foo')); - Assert::same('FooModule\BarPresenter', $factory->formatPresenterClass('Foo:Bar')); - Assert::same('FooModule\BarModule\BazPresenter', $factory->formatPresenterClass('Foo:Bar:Baz')); + Assert::same('App\UI\Foo\FooPresenter', $factory->formatPresenterClass('Foo')); + Assert::same('App\UI\Foo\Bar\BarPresenter', $factory->formatPresenterClass('Foo:Bar')); + Assert::same('App\UI\Foo\Bar\Baz\BazPresenter', $factory->formatPresenterClass('Foo:Bar:Baz')); - Assert::same('Foo2Presenter', $factory->formatPresenterClass('Foo2')); + Assert::same('App\UI\Foo2\Foo2Presenter', $factory->formatPresenterClass('Foo2')); Assert::same('App2\Bar\BarPresenter', $factory->formatPresenterClass('Foo2:Bar')); Assert::same('App2\Bar\Baz\BazPresenter', $factory->formatPresenterClass('Foo2:Bar:Baz')); diff --git a/tests/Routers/LinkGenerator.phpt b/tests/Routers/LinkGenerator.phpt index 3acc40491..cc88b4ac2 100644 --- a/tests/Routers/LinkGenerator.phpt +++ b/tests/Routers/LinkGenerator.phpt @@ -6,7 +6,9 @@ declare(strict_types=1); -namespace { +namespace App\UI\Homepage { + + use Nette; require __DIR__ . '/../bootstrap.php'; @@ -24,7 +26,7 @@ namespace { } -namespace ModuleModule { +namespace App\UI\Module\My { use Nette; @@ -77,7 +79,7 @@ namespace { Assert::exception(function () use ($pf) { $generator = new LinkGenerator(new Routers\Route('/', 'Homepage:'), new Http\UrlScript('http://nette.org/en/'), $pf); $generator->link('Homepage:missing', [10]); - }, Nette\Application\UI\InvalidLinkException::class, "Unable to pass parameters to action 'Homepage:missing', missing corresponding method HomepagePresenter::renderMissing()."); + }, Nette\Application\UI\InvalidLinkException::class, "Unable to pass parameters to action 'Homepage:missing', missing corresponding method App\\UI\\Homepage\\HomepagePresenter::renderMissing()."); test('', function () { diff --git a/tests/Routers/link-aliases.phpt b/tests/Routers/link-aliases.phpt index 0f2b75324..2180bd526 100644 --- a/tests/Routers/link-aliases.phpt +++ b/tests/Routers/link-aliases.phpt @@ -20,6 +20,7 @@ class TestPresenter extends Application\UI\Presenter $factory = new PresenterFactory; +$factory->setMapping(['*' => '*Presenter']); $factory->setAliases([ 'a' => 'Test:a', 'b' => 'Test:b', From 9a0af139771a45307d5ce03e0543850753b55063 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 22 Jan 2024 00:20:18 +0100 Subject: [PATCH 19/21] uses nette/routing 4.0 --- src/Application/Routers/RouteList.php | 4 ++-- src/Bridges/ApplicationTracy/RoutingPanel.php | 2 +- tests/Routers/RouteList.addRoute.phpt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Application/Routers/RouteList.php b/src/Application/Routers/RouteList.php index 1305cc64e..6ed3d079c 100644 --- a/src/Application/Routers/RouteList.php +++ b/src/Application/Routers/RouteList.php @@ -65,10 +65,10 @@ public function addRoute( #[Language('TEXT')] string $mask, array|string|\Closure $metadata = [], - int|bool $oneWay = 0, + bool $oneWay = false, ): static { - $this->add(new Route($mask, $metadata), (int) $oneWay); + $this->add(new Route($mask, $metadata), $oneWay); return $this; } diff --git a/src/Bridges/ApplicationTracy/RoutingPanel.php b/src/Bridges/ApplicationTracy/RoutingPanel.php index a69c429dc..a48813ba6 100644 --- a/src/Bridges/ApplicationTracy/RoutingPanel.php +++ b/src/Bridges/ApplicationTracy/RoutingPanel.php @@ -85,7 +85,7 @@ private function analyse(Routing\RouteList $router, ?Nette\Http\IRequest $httpRe continue; } - $matched = $flags[$i] & $router::ONE_WAY ? 'oneway' : 'no'; + $matched = empty($flags[$i]['oneWay']) ? 'no' : 'oneway'; $params = $e = null; try { if ( diff --git a/tests/Routers/RouteList.addRoute.phpt b/tests/Routers/RouteList.addRoute.phpt index fd6ab423a..068f66805 100644 --- a/tests/Routers/RouteList.addRoute.phpt +++ b/tests/Routers/RouteList.addRoute.phpt @@ -12,7 +12,7 @@ require __DIR__ . '/Route.php'; $list = new RouteList; $list->addRoute('foo', ['presenter' => 'foo'], RouteList::ONE_WAY); -$list->addRoute('bar', ['presenter' => 'bar'], RouteList::ONE_WAY); +$list->addRoute('bar', ['presenter' => 'bar'], oneWay: true); $list->addRoute('hello', ['presenter' => 'hello']); From ecb200c743439c2d7a781f92f9f626e06ec191c8 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 9 Jan 2023 14:07:48 +0100 Subject: [PATCH 20/21] LatteExtension: added option 'variables' --- src/Bridges/ApplicationDI/LatteExtension.php | 7 +- .../ApplicationLatte/DefaultTemplate.php | 1 + .../ApplicationLatte/TemplateFactory.php | 2 + .../Bridges.DI/LatteExtension.variables.phpt | 74 +++++++++++++++++++ 4 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 tests/Bridges.DI/LatteExtension.variables.phpt diff --git a/src/Bridges/ApplicationDI/LatteExtension.php b/src/Bridges/ApplicationDI/LatteExtension.php index f26c5d393..82d0c08dd 100644 --- a/src/Bridges/ApplicationDI/LatteExtension.php +++ b/src/Bridges/ApplicationDI/LatteExtension.php @@ -38,6 +38,7 @@ public function getConfigSchema(): Nette\Schema\Schema 'strictTypes' => Expect::bool(false), 'strictParsing' => Expect::bool(false), 'phpLinter' => Expect::string(), + 'variables' => Expect::array([]), ]); } @@ -75,8 +76,10 @@ public function loadConfiguration(): void } $builder->addDefinition($this->prefix('templateFactory')) - ->setFactory(ApplicationLatte\TemplateFactory::class) - ->setArguments(['templateClass' => $config->templateClass]); + ->setFactory(ApplicationLatte\TemplateFactory::class, [ + 'templateClass' => $config->templateClass, + 'configVars' => $config->variables, + ]); if ($this->name === 'latte') { $builder->addAlias('nette.latteFactory', $this->prefix('latteFactory')); diff --git a/src/Bridges/ApplicationLatte/DefaultTemplate.php b/src/Bridges/ApplicationLatte/DefaultTemplate.php index 29d761663..85eae9c6d 100644 --- a/src/Bridges/ApplicationLatte/DefaultTemplate.php +++ b/src/Bridges/ApplicationLatte/DefaultTemplate.php @@ -29,6 +29,7 @@ final class DefaultTemplate extends Template /** @var \stdClass[] */ public array $flashes = []; + public \stdClass $config; /** diff --git a/src/Bridges/ApplicationLatte/TemplateFactory.php b/src/Bridges/ApplicationLatte/TemplateFactory.php index 1f2cbb764..5dc9cf50f 100644 --- a/src/Bridges/ApplicationLatte/TemplateFactory.php +++ b/src/Bridges/ApplicationLatte/TemplateFactory.php @@ -28,6 +28,7 @@ public function __construct( private readonly ?Nette\Http\IRequest $httpRequest = null, private readonly ?Nette\Security\User $user = null, $templateClass = null, + private array $configVars = [], ) { if ($templateClass && (!class_exists($templateClass) || !is_a($templateClass, Template::class, true))) { throw new Nette\InvalidArgumentException("Class $templateClass does not implement " . Template::class . ' or it does not exist.'); @@ -63,6 +64,7 @@ public function createTemplate(?UI\Control $control = null, ?string $class = nul 'flashes' => $flashes, 'control' => $control, 'presenter' => $presenter, + 'config' => $control instanceof UI\Presenter && $this->configVars ? (object) $this->configVars : null, ]; foreach ($params as $key => $value) { diff --git a/tests/Bridges.DI/LatteExtension.variables.phpt b/tests/Bridges.DI/LatteExtension.variables.phpt new file mode 100644 index 000000000..c7051e5d8 --- /dev/null +++ b/tests/Bridges.DI/LatteExtension.variables.phpt @@ -0,0 +1,74 @@ +load(Tester\FileMock::create(' + latte: + variables: + ', 'neon')); + + $compiler = new DI\Compiler; + $compiler->addExtension('latte', new Nette\Bridges\ApplicationDI\LatteExtension('', false)); + $code = $compiler + ->addConfig($config) + ->setClassName('Container1') + ->compile(); + eval($code); + + $container = new Container1; + $latteFactory = $container->getService('latte.templateFactory'); + $presenter = Mockery::mock(Nette\Application\UI\Presenter::class); + $presenter->shouldReceive('getHttpResponse')->andReturn(Mockery::mock(Nette\Http\IResponse::class)->shouldIgnoreMissing()); + $presenter->shouldIgnoreMissing(); + + $template = $latteFactory->createTemplate($presenter); + Assert::notContains('config', $template->getParameters()); +}); + + +test('presenter presence', function () { + $loader = new DI\Config\Loader; + $config = $loader->load(Tester\FileMock::create(' + latte: + variables: + foo: bar + ', 'neon')); + + $compiler = new DI\Compiler; + $compiler->addExtension('latte', new Nette\Bridges\ApplicationDI\LatteExtension('', false)); + $code = $compiler + ->addConfig($config) + ->setClassName('Container2') + ->compile(); + eval($code); + + $container = new Container2; + $latteFactory = $container->getService('latte.templateFactory'); + $template = $latteFactory->createTemplate(); + Assert::notContains('config', $template->getParameters()); + + + $presenter = Mockery::mock(Nette\Application\UI\Presenter::class); + $presenter->shouldReceive('getHttpResponse')->andReturn(Mockery::mock(Nette\Http\IResponse::class)->shouldIgnoreMissing()); + $presenter->shouldIgnoreMissing(); + + $template = $latteFactory->createTemplate($presenter); + Assert::equal( + (object) ['foo' => 'bar'], + $template->getParameters()['config'], + ); +}); From 83880f2d91d29be92fbd66bd4d0052c318be93f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20Brecher?= <34324008+mildabre@users.noreply.github.com> Date: Wed, 29 May 2024 01:56:16 +0200 Subject: [PATCH 21/21] Correction of false exception message in startup check The exception message states the lowest possible presenter class where method beforeRender is found, so the error can be here or in its parents not descendants !! --- src/Application/UI/Presenter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index 82bf72c92..000128b6d 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -189,7 +189,7 @@ public function run(Application\Request $request): Application\Response $this->startup(); if (!$this->startupCheck) { $class = static::getReflection()->getMethod('startup')->getDeclaringClass()->getName(); - throw new Nette\InvalidStateException("Method $class::startup() or its descendant doesn't call parent::startup()."); + throw new Nette\InvalidStateException("Method $class::startup() or its parents doesn't call parent::startup()."); } // calls $this->action()