diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md deleted file mode 100644 index a4cd12634..000000000 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: "🐛 Bug Report" -about: "If something isn't working as expected 🤔" - ---- - -Version: ?.?.? - -### Bug Description -... A clear and concise description of what the bug is. A good bug report shouldn't leave others needing to chase you up for more information. - -### Steps To Reproduce -... If possible a minimal demo of the problem ... - -### Expected Behavior -... A clear and concise description of what you expected to happen. - -### Possible Solution -... Only if you have suggestions on a fix for the bug diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md deleted file mode 100644 index d2e219489..000000000 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: "🚀 Feature Request" -about: "I have a suggestion (and may want to implement it) 🙂" - ---- - -- Is your feature request related to a problem? Please describe. -- Explain your intentions. -- It's up to you to make a strong case to convince the project's developers of the merits of this feature. diff --git a/.github/ISSUE_TEMPLATE/Support_question.md b/.github/ISSUE_TEMPLATE/Support_question.md deleted file mode 100644 index 75c48b6ed..000000000 --- a/.github/ISSUE_TEMPLATE/Support_question.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: "🤗 Support Question" -about: "If you have a question 💬, please check out our forum!" - ---- - ---------------^ Click "Preview" for a nicer view! -We primarily use GitHub as an issue tracker; for usage and support questions, please check out these resources below. Thanks! 😁. - -* Nette Forum: https://forum.nette.org -* Nette Gitter: https://gitter.im/nette/nette -* Slack (czech): https://pehapkari.slack.com/messages/C2R30BLKA diff --git a/.github/ISSUE_TEMPLATE/Support_us.md b/.github/ISSUE_TEMPLATE/Support_us.md deleted file mode 100644 index 92d8a4c3a..000000000 --- a/.github/ISSUE_TEMPLATE/Support_us.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: "❤️ Support us" -about: "If you would like to support our efforts in maintaining this project 🙌" - ---- - ---------------^ Click "Preview" for a nicer view! - -> https://nette.org/donate - -Help support Nette! - -We develop Nette Framework for more than 14 years. In order to make your life more comfortable. Nette cares about the safety of your sites. Nette saves you time. And gives job opportunities. - -Nette earns you money. And is absolutely free. - -To ensure future development and improving the documentation, we need your donation. - -Whether you are chief of IT company which benefits from Nette, or developer who goes for advice on our forum, if you like Nette, [please make a donation now](https://nette.org/donate). - -Thank you! diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index 25adc9520..000000000 --- a/.github/funding.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: dg -custom: "https://nette.org/donate" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index f8aa3f408..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,11 +0,0 @@ -- bug fix / new feature? -- BC break? yes/no -- doc PR: nette/docs#??? - - diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index c32a75810..c7ae52238 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 coverage: none - run: composer install --no-progress --prefer-dist diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index efc34d490..239bdc4d2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + php: ['8.0', '8.1', '8.2'] fail-fast: false @@ -35,7 +35,7 @@ jobs: - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: - php-version: 7.2 + php-version: 8.0 coverage: none - run: composer update --no-progress --prefer-dist --prefer-lowest --prefer-stable diff --git a/composer.json b/composer.json index a3bb333aa..610c00d48 100644 --- a/composer.json +++ b/composer.json @@ -15,15 +15,15 @@ } ], "require": { - "php": ">=7.2 <8.3", - "nette/component-model": "^3.0", - "nette/http": "^3.1", - "nette/utils": "^3.2.5 || ~4.0.0" + "php": ">=8.0 <8.3", + "nette/component-model": "^4.0", + "nette/http": "^4.0", + "nette/utils": "^4.0" }, "require-dev": { - "nette/application": "^3.0", - "nette/di": "^3.0", - "nette/tester": "^2.4", + "nette/application": "^4.0", + "nette/di": "^3.1 || ^4.0", + "nette/tester": "^2.5", "latte/latte": "^2.10.2 || ^3.0.3", "tracy/tracy": "^2.9", "phpstan/phpstan-nette": "^1" @@ -41,7 +41,7 @@ }, "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "4.0-dev" } } } diff --git a/contributing.md b/contributing.md deleted file mode 100644 index 184152c02..000000000 --- a/contributing.md +++ /dev/null @@ -1,33 +0,0 @@ -How to contribute & use the issue tracker -========================================= - -Nette welcomes your contributions. There are several ways to help out: - -* Create an issue on GitHub, if you have found a bug -* Write test cases for open bug issues -* Write fixes for open bug/feature issues, preferably with test cases included -* Contribute to the [documentation](https://nette.org/en/writing) - -Issues ------- - -Please **do not use the issue tracker to ask questions**. We will be happy to help you -on [Nette forum](https://forum.nette.org) or chat with us on [Gitter](https://gitter.im/nette/nette). - -A good bug report shouldn't leave others needing to chase you up for more -information. Please try to be as detailed as possible in your report. - -**Feature requests** are welcome. But take a moment to find out whether your idea -fits with the scope and aims of the project. It's up to *you* to make a strong -case to convince the project's developers of the merits of this feature. - -Contributing ------------- - -If you'd like to contribute, please take a moment to read [the contributing guide](https://nette.org/en/contributing). - -The best way to propose a feature is to discuss your ideas on [Nette forum](https://forum.nette.org) before implementing them. - -Please do not fix whitespace, format code, or make a purely cosmetic patch. - -Thanks! :heart: diff --git a/examples/custom-control.php b/examples/custom-control.php index d8c1041da..1db53b81c 100644 --- a/examples/custom-control.php +++ b/examples/custom-control.php @@ -18,12 +18,11 @@ class DateInput extends Nette\Forms\Controls\BaseControl { - /** @var string */ - private $day = ''; + private string $day = ''; - private $month = ''; + private string $month = ''; - private $year = ''; + private string $year = ''; public function __construct($label = null) @@ -88,7 +87,7 @@ public function getControl() . Helpers::createSelectBox( [1 => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [], - $this->month + $this->month, )->name($name . '[month]') . Html::el('input', [ diff --git a/readme.md b/readme.md index fe20b2ab8..090633666 100644 --- a/readme.md +++ b/readme.md @@ -44,7 +44,7 @@ The recommended way to install is via Composer: composer require nette/forms ``` -It requires PHP version 7.2 and supports PHP up to 8.2. +It requires PHP version 8.0 and supports PHP up to 8.2. Client-side support can be installed with npm or yarn: diff --git a/src/Bridges/FormsDI/FormsExtension.php b/src/Bridges/FormsDI/FormsExtension.php index 58281781b..5b4989f89 100644 --- a/src/Bridges/FormsDI/FormsExtension.php +++ b/src/Bridges/FormsDI/FormsExtension.php @@ -21,7 +21,7 @@ public function __construct() { $this->config = new class { /** @var string[] */ - public $messages = []; + public array $messages = []; }; } diff --git a/src/Bridges/FormsLatte/FormMacros.php b/src/Bridges/FormsLatte/FormMacros.php index 736ca3349..f05d50488 100644 --- a/src/Bridges/FormsLatte/FormMacros.php +++ b/src/Bridges/FormsLatte/FormMacros.php @@ -31,7 +31,7 @@ final class FormMacros extends MacroSet public static function install(Latte\Compiler $compiler): void { $me = new static($compiler); - $me->addMacro('form', [$me, 'macroForm'], 'echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack));'); + $me->addMacro('form', [$me, 'macroForm'], 'echo Nette\Bridges\FormsLatte\Runtime2::renderFormEnd(array_pop($this->global->formsStack));'); $me->addMacro('formContext', [$me, 'macroFormContext'], 'array_pop($this->global->formsStack);'); $me->addMacro('formContainer', [$me, 'macroFormContainer'], 'array_pop($this->global->formsStack); $formContainer = end($this->global->formsStack)'); $me->addMacro('label', [$me, 'macroLabel'], [$me, 'macroLabelEnd'], null, self::AUTO_EMPTY); @@ -67,12 +67,12 @@ public function macroForm(MacroNode $node, PhpWriter $writer) $node->replaced = true; $node->tokenizer->reset(); return $writer->write( - 'echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form = $this->global->formsStack[] = ' + 'echo Nette\Bridges\FormsLatte\Runtime2::renderFormBegin($form = $this->global->formsStack[] = ' . ($name[0] === '$' ? 'is_object($ʟ_tmp = %node.word) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]' : '$this->global->uiControl[%node.word]') . ', %node.array)' - . " /* line $node->startLine */;" + . " /* line $node->startLine */;", ); } @@ -101,7 +101,7 @@ public function macroFormContext(MacroNode $node, PhpWriter $writer) . ($name[0] === '$' ? 'is_object($ʟ_tmp = %node.word) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]' : '$this->global->uiControl[%node.word]') - . " /* line $node->startLine */;" + . " /* line $node->startLine */;", ); } @@ -126,7 +126,7 @@ public function macroFormContainer(MacroNode $node, PhpWriter $writer) . ($name[0] === '$' ? 'is_object($ʟ_tmp = %node.word) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp]' : 'end($this->global->formsStack)[%node.word]') - . " /* line $node->startLine */;" + . " /* line $node->startLine */;", ); } @@ -155,7 +155,7 @@ public function macroLabel(MacroNode $node, PhpWriter $writer) . '->%1.raw) echo $ʟ_label' . ($node->tokenizer->isNext() ? '->addAttributes(%node.array)' : ''), $name, - $words ? ('getLabelPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')') : 'getLabel()' + $words ? ('getLabelPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')') : 'getLabel()', ); } @@ -196,7 +196,7 @@ public function macroInput(MacroNode $node, PhpWriter $writer) . ($node->tokenizer->isNext() ? '->addAttributes(%node.array)' : '') . " /* line $node->startLine */;", $name, - $words ? 'getControlPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')' : 'getControl()' + $words ? 'getControlPart(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')' : 'getControl()', ); } @@ -227,11 +227,11 @@ public function macroNameAttr(MacroNode $node, PhpWriter $writer) ? 'is_object($ʟ_tmp = %0.word) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]' : '$this->global->uiControl[%0.word]') . " /* line $node->startLine */; ?>", - $name + $name, ); return $writer->write( - 'echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin(end($this->global->formsStack), %0.var, false)', - array_fill_keys($definedHtmlAttributes, null) + 'echo Nette\Bridges\FormsLatte\Runtime2::renderFormBegin(end($this->global->formsStack), %0.var, false)', + array_fill_keys($definedHtmlAttributes, null), ); } else { $method = $tagName === 'label' ? 'getLabel' : 'getControl'; @@ -245,7 +245,7 @@ public function macroNameAttr(MacroNode $node, PhpWriter $writer) . " /* line $node->startLine */;", $name, $method . 'Part(' . implode(', ', array_map([$writer, 'formatWord'], $words)) . ')', - array_fill_keys($definedHtmlAttributes, null) + array_fill_keys($definedHtmlAttributes, null), ); } } @@ -265,7 +265,7 @@ public function macroNameEnd(MacroNode $node, PhpWriter $writer) { $tagName = strtolower($node->htmlNode->name); if ($tagName === 'form') { - $node->innerContent .= 'global->formsStack), false)' + $node->innerContent .= 'global->formsStack), false)' . " /* line $node->startLine */; ?>"; } elseif ($tagName === 'label') { if ($node->htmlNode->empty) { @@ -298,7 +298,7 @@ public function macroInputError(MacroNode $node, PhpWriter $writer) return $writer->write( '$ʟ_input = is_object($ʟ_tmp = %0.word) ? $ʟ_tmp : end($this->global->formsStack)[$ʟ_tmp];' . "echo %escape(\$ʟ_input->getError()) /* line $node->startLine */;", - $name + $name, ); } else { return $writer->write("echo %escape(end(\$this->global->formsStack)[%0.word]->getError()) /* line $node->startLine */;", $name); @@ -319,11 +319,9 @@ public function macroFormPrint(MacroNode $node, PhpWriter $writer) $node->tokenizer->reset(); return $writer->write( - 'Nette\Bridges\FormsLatte\Runtime::render' . $node->name . '(' - . ($name[0] === '$' - ? 'is_object($ʟ_tmp = %node.word) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]' - : '$this->global->uiControl[%node.word]') - . '); exit;' + 'Nette\Bridges\FormsLatte\Runtime2::render' . $node->name . '(' + . ($name[0] === '$' ? 'is_object(%node.word) ? %node.word : ' : '') + . '$this->global->uiControl[%node.word]); exit;', ); } } diff --git a/src/Bridges/FormsLatte/FormsExtension.php b/src/Bridges/FormsLatte/FormsExtension.php index 3e13a0b88..92dd0b20d 100644 --- a/src/Bridges/FormsLatte/FormsExtension.php +++ b/src/Bridges/FormsLatte/FormsExtension.php @@ -38,7 +38,13 @@ public function getTags(): array public function getProviders(): array { return [ - 'formsStack' => [], + 'forms' => new Runtime, ]; } + + + public function getCacheKey(Latte\Engine $engine): array + { + return ['version' => 2]; + } } diff --git a/src/Bridges/FormsLatte/Nodes/FieldNNameNode.php b/src/Bridges/FormsLatte/Nodes/FieldNNameNode.php index 78ce293a6..bbf3681ea 100644 --- a/src/Bridges/FormsLatte/Nodes/FieldNNameNode.php +++ b/src/Bridges/FormsLatte/Nodes/FieldNNameNode.php @@ -64,7 +64,7 @@ private function init(Tag $tag) $elName = strtolower($el->name); $tag->replaceNAttribute(new AuxiliaryNode(fn(PrintContext $context) => $context->format( - 'echo ($ʟ_input = Nette\Bridges\FormsLatte\Runtime::item(%node, $this->global))' + 'echo ($ʟ_input = $this->global->forms->item(%node))' . ($elName === 'label' ? '->getLabelPart(%node)' : '->getControlPart(%node)') . ($usedAttributes ? '->addAttributes(%dump)' : '') . '->attributes() %3.line;', diff --git a/src/Bridges/FormsLatte/Nodes/FormContainerNode.php b/src/Bridges/FormsLatte/Nodes/FormContainerNode.php index 36cd2aa9f..9569d8a85 100644 --- a/src/Bridges/FormsLatte/Nodes/FormContainerNode.php +++ b/src/Bridges/FormsLatte/Nodes/FormContainerNode.php @@ -41,9 +41,9 @@ public static function create(Tag $tag): \Generator public function print(PrintContext $context): string { return $context->format( - '$this->global->formsStack[] = $formContainer = Nette\Bridges\FormsLatte\Runtime::item(%node, $this->global) %line; ' + '$this->global->forms->begin($formContainer = $this->global->forms->item(%node)) %line; ' . '%node ' - . 'array_pop($this->global->formsStack); $formContainer = end($this->global->formsStack);' + . '$this->global->forms->end(); $formContainer = $this->global->forms->current();' . "\n\n", $this->name, $this->position, diff --git a/src/Bridges/FormsLatte/Nodes/FormNNameNode.php b/src/Bridges/FormsLatte/Nodes/FormNNameNode.php index 2de161e4a..b46ceb866 100644 --- a/src/Bridges/FormsLatte/Nodes/FormNNameNode.php +++ b/src/Bridges/FormsLatte/Nodes/FormNNameNode.php @@ -42,13 +42,13 @@ public static function create(Tag $tag): \Generator public function print(PrintContext $context): string { return $context->format( - '$form = $this->global->formsStack[] = ' + '$this->global->forms->begin($form = ' . ($this->name instanceof StringNode ? '$this->global->uiControl[%node]' - : 'is_object($ʟ_tmp = %node) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]') - . ' %line;' + : '(is_object($ʟ_tmp = %node) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp])') + . ') %line;' . '%node ' - . 'array_pop($this->global->formsStack);', + . '$this->global->forms->end();', $this->name, $this->position, $this->content, @@ -61,7 +61,7 @@ private function init(Tag $tag) $el = $tag->htmlElement; $tag->replaceNAttribute(new AuxiliaryNode(fn(PrintContext $context) => $context->format( - 'echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin(end($this->global->formsStack), %dump, false) %line;', + 'echo $this->global->forms->renderFormBegin(%dump, false) %line;', array_fill_keys(FieldNNameNode::findUsedAttributes($el), null), $this->position, ))); @@ -69,7 +69,7 @@ private function init(Tag $tag) $el->content = new Latte\Compiler\Nodes\FragmentNode([ $el->content, new AuxiliaryNode(fn(PrintContext $context) => $context->format( - 'echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(end($this->global->formsStack), false) %line;', + 'echo $this->global->forms->renderFormEnd(false) %line;', $this->position, )), ]); diff --git a/src/Bridges/FormsLatte/Nodes/FormNode.php b/src/Bridges/FormsLatte/Nodes/FormNode.php index c2902d78d..b98d6e3f9 100644 --- a/src/Bridges/FormsLatte/Nodes/FormNode.php +++ b/src/Bridges/FormsLatte/Nodes/FormNode.php @@ -61,19 +61,21 @@ public static function create(Tag $tag): \Generator public function print(PrintContext $context): string { return $context->format( - '$form = $this->global->formsStack[] = ' + '$this->global->forms->begin($form = ' . ($this->name instanceof StringNode ? '$this->global->uiControl[%node]' - : 'is_object($ʟ_tmp = %node) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]') - . ' %line;' + : '(is_object($ʟ_tmp = %node) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp])') + . ') %line;' . ($this->print - ? 'echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form, %node) %1.line;' + ? 'echo $this->global->forms->renderFormBegin(%node) %1.line;' : '') . ' %3.node ' . ($this->print - ? 'echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd(array_pop($this->global->formsStack))' - : 'array_pop($this->global->formsStack)') - . " %4.line;\n\n", + ? 'echo $this->global->forms->renderFormEnd()' + : '') + . ' %4.line;' + . '$this->global->forms->end();' + . "\n\n", $this->name, $this->position, $this->attributes, diff --git a/src/Bridges/FormsLatte/Nodes/FormPrintNode.php b/src/Bridges/FormsLatte/Nodes/FormPrintNode.php index 427beedbb..eb25d4b2c 100644 --- a/src/Bridges/FormsLatte/Nodes/FormPrintNode.php +++ b/src/Bridges/FormsLatte/Nodes/FormPrintNode.php @@ -39,10 +39,10 @@ public static function create(Tag $tag): static public function print(PrintContext $context): string { return $context->format( - 'Nette\Bridges\FormsLatte\Runtime::render%raw(' + '$this->global->forms->render%raw(' . ($this->name ? 'is_object($ʟ_tmp = %node) ? $ʟ_tmp : $this->global->uiControl[$ʟ_tmp]' - : 'end($this->global->formsStack)') + : '$this->global->forms->current()') . ') %2.line; exit;', $this->mode, $this->name, diff --git a/src/Bridges/FormsLatte/Nodes/InputErrorNode.php b/src/Bridges/FormsLatte/Nodes/InputErrorNode.php index ba2767a61..c30a6bba4 100644 --- a/src/Bridges/FormsLatte/Nodes/InputErrorNode.php +++ b/src/Bridges/FormsLatte/Nodes/InputErrorNode.php @@ -9,7 +9,6 @@ namespace Nette\Bridges\FormsLatte\Nodes; -use Latte\Compiler\Nodes\Php\Expression\VariableNode; use Latte\Compiler\Nodes\Php\ExpressionNode; use Latte\Compiler\Nodes\StatementNode; use Latte\Compiler\PrintContext; @@ -27,13 +26,10 @@ class InputErrorNode extends StatementNode public static function create(Tag $tag): static { $tag->outputMode = $tag::OutputKeepIndentation; + $tag->expectArguments(); + $node = new static; - if ($tag->parser->isEnd()) { - trigger_error("Missing argument in {inputError} (on line {$tag->position->line})", E_USER_DEPRECATED); - $node->name = new VariableNode('ʟ_input'); - } else { - $node->name = $tag->parser->parseUnquotedStringOrExpression(); - } + $node->name = $tag->parser->parseUnquotedStringOrExpression(); return $node; } @@ -41,7 +37,7 @@ public static function create(Tag $tag): static public function print(PrintContext $context): string { return $context->format( - 'echo %escape(Nette\Bridges\FormsLatte\Runtime::item(%node, $this->global)->getError()) %line;', + 'echo %escape($this->global->forms->item(%node)->getError()) %line;', $this->name, $this->position, ); diff --git a/src/Bridges/FormsLatte/Nodes/InputNode.php b/src/Bridges/FormsLatte/Nodes/InputNode.php index d9f6841eb..be5a4e3b8 100644 --- a/src/Bridges/FormsLatte/Nodes/InputNode.php +++ b/src/Bridges/FormsLatte/Nodes/InputNode.php @@ -48,7 +48,7 @@ public static function create(Tag $tag): static public function print(PrintContext $context): string { return $context->format( - 'echo Nette\Bridges\FormsLatte\Runtime::item(%node, $this->global)->' + 'echo $this->global->forms->item(%node)->' . ($this->part ? ('getControlPart(%node)') : 'getControl()') . ($this->attributes->items ? '->addAttributes(%2.node)' : '') . ' %3.line;', diff --git a/src/Bridges/FormsLatte/Nodes/LabelNode.php b/src/Bridges/FormsLatte/Nodes/LabelNode.php index cf1316c59..82990d9e0 100644 --- a/src/Bridges/FormsLatte/Nodes/LabelNode.php +++ b/src/Bridges/FormsLatte/Nodes/LabelNode.php @@ -63,7 +63,7 @@ public static function create(Tag $tag): \Generator public function print(PrintContext $context): string { return $context->format( - 'echo ($ʟ_label = Nette\Bridges\FormsLatte\Runtime::item(%node, $this->global)->' + 'echo ($ʟ_label = $this->global->forms->item(%node)->' . ($this->part ? 'getLabelPart(%node)' : 'getLabel()') . ')' . ($this->attributes->items ? '?->addAttributes(%2.node)' : '') diff --git a/src/Bridges/FormsLatte/Runtime.php b/src/Bridges/FormsLatte/Runtime.php index 0de03a92b..d1f55f28a 100644 --- a/src/Bridges/FormsLatte/Runtime.php +++ b/src/Bridges/FormsLatte/Runtime.php @@ -11,23 +11,27 @@ use Latte; use Nette; +use Nette\Forms\Container; use Nette\Forms\Form; use Nette\Utils\Html; /** - * Runtime helpers for Latte v2 & v3. + * Runtime helpers for Latte v3. * @internal */ class Runtime { - use Nette\StaticClass; + /** @var Container[] */ + private array $stack = []; + /** * Renders form begin. */ - public static function renderFormBegin(Form $form, array $attrs, bool $withTags = true): string + public function renderFormBegin(array $attrs, bool $withTags = true): string { + $form = $this->current(); $form->fireRenderEvents(); foreach ($form->getControls() as $control) { $control->setOption('rendered', false); @@ -48,8 +52,9 @@ public static function renderFormBegin(Form $form, array $attrs, bool $withTags /** * Renders form end. */ - public static function renderFormEnd(Form $form, bool $withTags = true): string + public function renderFormEnd(bool $withTags = true): string { + $form = $this->current(); $s = ''; if ($form->isMethod('get')) { foreach (preg_split('#[;&]#', (string) parse_url($form->getElementPrototype()->action, PHP_URL_QUERY), -1, PREG_SPLIT_NO_EMPTY) as $param) { @@ -79,7 +84,7 @@ public static function renderFormEnd(Form $form, bool $withTags = true): string /** * Generates blueprint of form. */ - public static function renderFormPrint(Form $form): void + public function renderFormPrint(Form $form): void { $blueprint = class_exists(Latte\Runtime\Blueprint::class) ? new Latte\Runtime\Blueprint @@ -94,7 +99,7 @@ public static function renderFormPrint(Form $form): void /** * Generates blueprint of form data class. */ - public static function renderFormClassPrint(Form $form): void + public function renderFormClassPrint(Form $form): void { $blueprint = class_exists(Latte\Runtime\Blueprint::class) ? new Latte\Runtime\Blueprint @@ -103,24 +108,35 @@ public static function renderFormClassPrint(Form $form): void $blueprint->printHeader('Form Data Class ' . $form->getName()); $generator = new Nette\Forms\Rendering\DataClassGenerator; $blueprint->printCode($generator->generateCode($form)); - if (PHP_VERSION_ID >= 80000) { - $generator->propertyPromotion = true; - $blueprint->printCode($generator->generateCode($form)); - } + $generator->propertyPromotion = true; + $blueprint->printCode($generator->generateCode($form)); echo $end; } - public static function item($item, $global): object + public function item($item): object { - if (is_object($item)) { - return $item; - } - $form = end($global->formsStack); - if (!$form) { - throw new \LogicException('Form declaration is missing, did you use {form} or
', - $res + $res, ); diff --git a/tests/Forms/Rules.valid.phpt b/tests/Forms/Rules.valid.phpt index 82efe3a0b..0c085708d 100644 --- a/tests/Forms/Rules.valid.phpt +++ b/tests/Forms/Rules.valid.phpt @@ -45,9 +45,7 @@ test('', function () { test('', function () { $form = new Form; $form->addText('foo') - ->addFilter(function ($value) { - return str_replace(' ', '', $value); - }) + ->addFilter(fn($value) => str_replace(' ', '', $value)) ->addRule($form::Pattern, 'only numbers', '\d{5}'); $form['foo']->setValue('160 00'); @@ -65,9 +63,7 @@ test('', function () { $foo = $form->addText('foo'); $rules = $foo->getRules(); $rules->addFilter( - function ($value) { - return str_replace(' ', '', $value); - } + fn($value) => str_replace(' ', '', $value), ); $rules->addRule($form::Pattern, 'only numbers', '\d{5}'); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index abb911275..67c2ed86d 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -12,21 +12,4 @@ Tester\Environment::setup(); -date_default_timezone_set('Europe/Prague'); - - -function before(?Closure $function = null) -{ - static $val; - if (!func_num_args()) { - return $val ? $val() : null; - } - $val = $function; -} - - -function test(string $title, Closure $function): void -{ - before(); - $function(); -} +Tester\Environment::setupFunctions(); diff --git a/tests/types/ControlsReturnTypeTest.php b/tests/types/ControlsReturnTypeTest.php new file mode 100644 index 000000000..d7ba40882 --- /dev/null +++ b/tests/types/ControlsReturnTypeTest.php @@ -0,0 +1,31 @@ + */ + public function dataFileAsserts(): iterable + { + yield from $this->gatherAssertTypes(__DIR__ . '/data/Controls.getValue().php'); + } + + + /** @dataProvider dataFileAsserts */ + public function testFileAsserts(string $assertType, string $file, mixed ...$args): void + { + $this->assertFileAsserts($assertType, $file, ...$args); + } +} + + +$testCase = new ControlsReturnTypeTest; +$testCase->run(); diff --git a/tests/types/TestCase.php b/tests/types/TestCase.php new file mode 100644 index 000000000..02f87fa4b --- /dev/null +++ b/tests/types/TestCase.php @@ -0,0 +1,28 @@ +addText('Text'); +assertType('string|null', $input->getValue()); + +$input = $form->addPassword('Password'); +assertType('string|null', $input->getValue()); + +$input = $form->addTextArea('TextArea'); +assertType('string|null', $input->getValue()); + +$input = $form->addEmail('Email'); +assertType('string|null', $input->getValue()); + +$input = $form->addInteger('Integer'); +assertType('string|null', $input->getValue()); + +$input = $form->addUpload('Upload'); +assertType('array