diff --git a/Attribute/Template.php b/Attribute/Template.php
index e265e239..ef2f193b 100644
--- a/Attribute/Template.php
+++ b/Attribute/Template.php
@@ -21,11 +21,13 @@ class Template
* @param string $template The name of the template to render
* @param string[]|null $vars The controller method arguments to pass to the template
* @param bool $stream Enables streaming the template
+ * @param string|null $block The name of the block to use in the template
*/
public function __construct(
public string $template,
public ?array $vars = null,
public bool $stream = false,
+ public ?string $block = null,
) {
}
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index df8f28f0..b18e2745 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========
+7.2
+---
+
+ * Deprecate passing a tag to the constructor of `FormThemeNode`
+
7.1
---
diff --git a/Command/DebugCommand.php b/Command/DebugCommand.php
index 0eaacfbf..c145a7ef 100644
--- a/Command/DebugCommand.php
+++ b/Command/DebugCommand.php
@@ -57,7 +57,7 @@ protected function configure(): void
->setDefinition([
new InputArgument('name', InputArgument::OPTIONAL, 'The template name'),
new InputOption('filter', null, InputOption::VALUE_REQUIRED, 'Show details for all entries matching this filter'),
- new InputOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'text'),
+ new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'txt'),
])
->setHelp(<<<'EOF'
The %command.name% command outputs a list of twig functions,
@@ -90,13 +90,19 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$filter = $input->getOption('filter');
if (null !== $name && [] === $this->getFilesystemLoaders()) {
- throw new InvalidArgumentException(sprintf('Argument "name" not supported, it requires the Twig loader "%s".', FilesystemLoader::class));
+ throw new InvalidArgumentException(\sprintf('Argument "name" not supported, it requires the Twig loader "%s".', FilesystemLoader::class));
}
- match ($input->getOption('format')) {
- 'text' => $name ? $this->displayPathsText($io, $name) : $this->displayGeneralText($io, $filter),
+ $format = $input->getOption('format');
+ if ('text' === $format) {
+ trigger_deprecation('symfony/twig-bridge', '7.2', 'The "text" format is deprecated, use "txt" instead.');
+
+ $format = 'txt';
+ }
+ match ($format) {
+ 'txt' => $name ? $this->displayPathsText($io, $name) : $this->displayGeneralText($io, $filter),
'json' => $name ? $this->displayPathsJson($io, $name) : $this->displayGeneralJson($io, $filter),
- default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
+ default => throw new InvalidArgumentException(\sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
};
return 0;
@@ -121,7 +127,7 @@ private function displayPathsText(SymfonyStyle $io, string $name): void
$io->section('Matched File');
if ($file->valid()) {
if ($fileLink = $this->getFileLink($file->key())) {
- $io->block($file->current(), 'OK', sprintf('fg=black;bg=green;href=%s', $fileLink), ' ', true);
+ $io->block($file->current(), 'OK', \sprintf('fg=black;bg=green;href=%s', $fileLink), ' ', true);
} else {
$io->success($file->current());
}
@@ -131,9 +137,9 @@ private function displayPathsText(SymfonyStyle $io, string $name): void
$io->section('Overridden Files');
do {
if ($fileLink = $this->getFileLink($file->key())) {
- $io->text(sprintf('* %s>', $fileLink, $file->current()));
+ $io->text(\sprintf('* %s>', $fileLink, $file->current()));
} else {
- $io->text(sprintf('* %s', $file->current()));
+ $io->text(\sprintf('* %s', $file->current()));
}
$file->next();
} while ($file->valid());
@@ -158,7 +164,7 @@ private function displayPathsText(SymfonyStyle $io, string $name): void
}
}
- $this->error($io, sprintf('Template name "%s" not found', $name), $alternatives);
+ $this->error($io, \sprintf('Template name "%s" not found', $name), $alternatives);
}
$io->section('Configured Paths');
@@ -171,7 +177,7 @@ private function displayPathsText(SymfonyStyle $io, string $name): void
if (FilesystemLoader::MAIN_NAMESPACE === $namespace) {
$message = 'No template paths configured for your application';
} else {
- $message = sprintf('No template paths configured for "@%s" namespace', $namespace);
+ $message = \sprintf('No template paths configured for "@%s" namespace', $namespace);
foreach ($this->getFilesystemLoaders() as $loader) {
$namespaces = $loader->getNamespaces();
foreach ($this->findAlternatives($namespace, $namespaces) as $namespace) {
@@ -199,7 +205,7 @@ private function displayPathsJson(SymfonyStyle $io, string $name): void
$data['overridden_files'] = $files;
}
} else {
- $data['matched_file'] = sprintf('Template name "%s" not found', $name);
+ $data['matched_file'] = \sprintf('Template name "%s" not found', $name);
}
$data['loader_paths'] = $paths;
@@ -338,15 +344,13 @@ private function getMetadata(string $type, mixed $entity): mixed
}
// format args
- $args = array_map(function (\ReflectionParameter $param) {
+ return array_map(function (\ReflectionParameter $param) {
if ($param->isDefaultValueAvailable()) {
return $param->getName().' = '.json_encode($param->getDefaultValue());
}
return $param->getName();
}, $args);
-
- return $args;
}
return null;
@@ -364,7 +368,7 @@ private function getPrettyMetadata(string $type, mixed $entity, bool $decorated)
return '(unknown?)';
}
} catch (\UnexpectedValueException $e) {
- return sprintf(' %s', $decorated ? OutputFormatter::escape($e->getMessage()) : $e->getMessage());
+ return \sprintf(' %s', $decorated ? OutputFormatter::escape($e->getMessage()) : $e->getMessage());
}
if ('globals' === $type) {
@@ -374,7 +378,7 @@ private function getPrettyMetadata(string $type, mixed $entity, bool $decorated)
$description = substr(@json_encode($meta), 0, 50);
- return sprintf(' = %s', $decorated ? OutputFormatter::escape($description) : $description);
+ return \sprintf(' = %s', $decorated ? OutputFormatter::escape($description) : $description);
}
if ('functions' === $type) {
@@ -408,7 +412,6 @@ private function findWrongBundleOverrides(): array
}
if ($notFoundBundles = array_diff_key($bundleNames, $this->bundlesMetadata)) {
- $alternatives = [];
foreach ($notFoundBundles as $notFoundBundle => $path) {
$alternatives[$path] = $this->findAlternatives($notFoundBundle, array_keys($this->bundlesMetadata));
}
@@ -421,14 +424,14 @@ private function buildWarningMessages(array $wrongBundles): array
{
$messages = [];
foreach ($wrongBundles as $path => $alternatives) {
- $message = sprintf('Path "%s" not matching any bundle found', $path);
+ $message = \sprintf('Path "%s" not matching any bundle found', $path);
if ($alternatives) {
if (1 === \count($alternatives)) {
- $message .= sprintf(", did you mean \"%s\"?\n", $alternatives[0]);
+ $message .= \sprintf(", did you mean \"%s\"?\n", $alternatives[0]);
} else {
$message .= ", did you mean one of these:\n";
foreach ($alternatives as $bundle) {
- $message .= sprintf(" - %s\n", $bundle);
+ $message .= \sprintf(" - %s\n", $bundle);
}
}
}
@@ -481,7 +484,7 @@ private function parseTemplateName(string $name, string $default = FilesystemLoa
{
if (isset($name[0]) && '@' === $name[0]) {
if (false === ($pos = strpos($name, '/')) || $pos === \strlen($name) - 1) {
- throw new InvalidArgumentException(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
+ throw new InvalidArgumentException(\sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
@@ -582,8 +585,9 @@ private function getFileLink(string $absolutePath): string
return (string) $this->fileLinkFormatter?->format($absolutePath, 1);
}
+ /** @return string[] */
private function getAvailableFormatOptions(): array
{
- return ['text', 'json'];
+ return ['txt', 'json'];
}
}
diff --git a/Command/LintCommand.php b/Command/LintCommand.php
index 14c00ba1..54720952 100644
--- a/Command/LintCommand.php
+++ b/Command/LintCommand.php
@@ -52,7 +52,7 @@ public function __construct(
protected function configure(): void
{
$this
- ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())))
+ ->addOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())))
->addOption('show-deprecations', null, InputOption::VALUE_NONE, 'Show deprecations as errors')
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
->addOption('excludes', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Excluded directories', [])
@@ -71,8 +71,10 @@ protected function configure(): void
Or of a whole directory:
php %command.full_name% dirname
- php %command.full_name% dirname --format=json
+The --format option specifies the format of the command output:
+
+ php %command.full_name% dirname --format=json
EOF
)
;
@@ -87,7 +89,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$this->format = $input->getOption('format') ?? (GithubActionReporter::isGithubActionEnvironment() ? 'github' : 'txt');
if (['-'] === $filenames) {
- return $this->display($input, $output, $io, [$this->validate(file_get_contents('php://stdin'), uniqid('sf_', true))]);
+ return $this->display($input, $output, $io, [$this->validate(file_get_contents('php://stdin'), 'Standard Input')]);
}
if (!$filenames) {
@@ -151,7 +153,7 @@ protected function findFiles(string $filename): iterable
return Finder::create()->files()->in($filename)->name($this->namePatterns)->exclude($this->excludes);
}
- throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
+ throw new RuntimeException(\sprintf('File or directory "%s" is not readable.', $filename));
}
private function validate(string $template, string $file): array
@@ -178,7 +180,7 @@ private function display(InputInterface $input, OutputInterface $output, Symfony
'txt' => $this->displayTxt($output, $io, $files),
'json' => $this->displayJson($output, $files),
'github' => $this->displayTxt($output, $io, $files, true),
- default => throw new InvalidArgumentException(sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
+ default => throw new InvalidArgumentException(\sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
};
}
@@ -189,7 +191,7 @@ private function displayTxt(OutputInterface $output, SymfonyStyle $io, array $fi
foreach ($filesInfo as $info) {
if ($info['valid'] && $output->isVerbose()) {
- $io->comment('OK'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
+ $io->comment('OK'.($info['file'] ? \sprintf(' in %s', $info['file']) : ''));
} elseif (!$info['valid']) {
++$errors;
$this->renderException($io, $info['template'], $info['exception'], $info['file'], $githubReporter);
@@ -197,9 +199,9 @@ private function displayTxt(OutputInterface $output, SymfonyStyle $io, array $fi
}
if (0 === $errors) {
- $io->success(sprintf('All %d Twig files contain valid syntax.', \count($filesInfo)));
+ $io->success(\sprintf('All %d Twig files contain valid syntax.', \count($filesInfo)));
} else {
- $io->warning(sprintf('%d Twig files have valid syntax and %d contain errors.', \count($filesInfo) - $errors, $errors));
+ $io->warning(\sprintf('%d Twig files have valid syntax and %d contain errors.', \count($filesInfo) - $errors, $errors));
}
return min($errors, 1);
@@ -231,28 +233,28 @@ private function renderException(SymfonyStyle $output, string $template, Error $
$githubReporter?->error($exception->getRawMessage(), $file, $line <= 0 ? null : $line);
if ($file) {
- $output->text(sprintf(' ERROR in %s (line %s)', $file, $line));
+ $output->text(\sprintf(' ERROR in %s (line %s)', $file, $line));
} else {
- $output->text(sprintf(' ERROR (line %s)', $line));
+ $output->text(\sprintf(' ERROR (line %s)', $line));
}
// If the line is not known (this might happen for deprecations if we fail at detecting the line for instance),
// we render the message without context, to ensure the message is displayed.
if ($line <= 0) {
- $output->text(sprintf(' >> %s ', $exception->getRawMessage()));
+ $output->text(\sprintf(' >> %s ', $exception->getRawMessage()));
return;
}
foreach ($this->getContext($template, $line) as $lineNumber => $code) {
- $output->text(sprintf(
+ $output->text(\sprintf(
'%s %-6s %s',
$lineNumber === $line ? ' >> ' : ' ',
$lineNumber,
$code
));
if ($lineNumber === $line) {
- $output->text(sprintf(' >> %s ', $exception->getRawMessage()));
+ $output->text(\sprintf(' >> %s ', $exception->getRawMessage()));
}
}
}
@@ -280,6 +282,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti
}
}
+ /** @return string[] */
private function getAvailableFormatOptions(): array
{
return ['txt', 'json', 'github'];
diff --git a/ErrorRenderer/TwigErrorRenderer.php b/ErrorRenderer/TwigErrorRenderer.php
index 0ea9b9aa..f624720b 100644
--- a/ErrorRenderer/TwigErrorRenderer.php
+++ b/ErrorRenderer/TwigErrorRenderer.php
@@ -69,7 +69,7 @@ public static function isDebug(RequestStack $requestStack, bool $debug): \Closur
private function findTemplate(int $statusCode): ?string
{
- $template = sprintf('@Twig/Exception/error%s.html.twig', $statusCode);
+ $template = \sprintf('@Twig/Exception/error%s.html.twig', $statusCode);
if ($this->twig->getLoader()->exists($template)) {
return $template;
}
diff --git a/EventListener/TemplateAttributeListener.php b/EventListener/TemplateAttributeListener.php
index f5962deb..45a4e9cc 100644
--- a/EventListener/TemplateAttributeListener.php
+++ b/EventListener/TemplateAttributeListener.php
@@ -55,8 +55,16 @@ public function onKernelView(ViewEvent $event): void
}
$event->setResponse($attribute->stream
- ? new StreamedResponse(fn () => $this->twig->display($attribute->template, $parameters), $status)
- : new Response($this->twig->render($attribute->template, $parameters), $status)
+ ? new StreamedResponse(
+ null !== $attribute->block
+ ? fn () => $this->twig->load($attribute->template)->displayBlock($attribute->block, $parameters)
+ : fn () => $this->twig->display($attribute->template, $parameters),
+ $status)
+ : new Response(
+ null !== $attribute->block
+ ? $this->twig->load($attribute->template)->renderBlock($attribute->block, $parameters)
+ : $this->twig->render($attribute->template, $parameters),
+ $status)
);
}
diff --git a/Extension/EmojiExtension.php b/Extension/EmojiExtension.php
index b98798da..c98a3aac 100644
--- a/Extension/EmojiExtension.php
+++ b/Extension/EmojiExtension.php
@@ -38,7 +38,7 @@ public function getFilters(): array
}
/**
- * Converts emoji short code (:wave:) to real emoji (👋)
+ * Converts emoji short code (:wave:) to real emoji (👋).
*/
public function emojify(string $string, ?string $catalog = null): string
{
@@ -47,7 +47,7 @@ public function emojify(string $string, ?string $catalog = null): string
try {
$tr = self::$transliterators[$catalog] ??= EmojiTransliterator::create($catalog, EmojiTransliterator::REVERSE);
} catch (\IntlException $e) {
- throw new \LogicException(sprintf('The emoji catalog "%s" is not available.', $catalog), previous: $e);
+ throw new \LogicException(\sprintf('The emoji catalog "%s" is not available.', $catalog), previous: $e);
}
return (string) $tr->transliterate($string);
diff --git a/Extension/HttpKernelRuntime.php b/Extension/HttpKernelRuntime.php
index 0aefed8f..6c488ef7 100644
--- a/Extension/HttpKernelRuntime.php
+++ b/Extension/HttpKernelRuntime.php
@@ -54,7 +54,7 @@ public function renderFragmentStrategy(string $strategy, string|ControllerRefere
public function generateFragmentUri(ControllerReference $controller, bool $absolute = false, bool $strict = true, bool $sign = true): string
{
if (null === $this->fragmentUriGenerator) {
- throw new \LogicException(sprintf('An instance of "%s" must be provided to use "%s()".', FragmentUriGeneratorInterface::class, __METHOD__));
+ throw new \LogicException(\sprintf('An instance of "%s" must be provided to use "%s()".', FragmentUriGeneratorInterface::class, __METHOD__));
}
return $this->fragmentUriGenerator->generate($controller, null, $absolute, $strict, $sign);
diff --git a/Extension/TranslationExtension.php b/Extension/TranslationExtension.php
index bf8b81bd..73c9ec85 100644
--- a/Extension/TranslationExtension.php
+++ b/Extension/TranslationExtension.php
@@ -44,10 +44,10 @@ public function getTranslator(): TranslatorInterface
{
if (null === $this->translator) {
if (!interface_exists(TranslatorInterface::class)) {
- throw new \LogicException(sprintf('You cannot use the "%s" if the Translation Contracts are not available. Try running "composer require symfony/translation".', __CLASS__));
+ throw new \LogicException(\sprintf('You cannot use the "%s" if the Translation Contracts are not available. Try running "composer require symfony/translation".', __CLASS__));
}
- $this->translator = new class() implements TranslatorInterface {
+ $this->translator = new class implements TranslatorInterface {
use TranslatorTrait;
};
}
@@ -97,7 +97,7 @@ public function trans(string|\Stringable|TranslatableInterface|null $message, ar
{
if ($message instanceof TranslatableInterface) {
if ([] !== $arguments && !\is_string($arguments)) {
- throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be a locale passed as a string when the message is a "%s", "%s" given.', __METHOD__, TranslatableInterface::class, get_debug_type($arguments)));
+ throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be a locale passed as a string when the message is a "%s", "%s" given.', __METHOD__, TranslatableInterface::class, get_debug_type($arguments)));
}
if ($message instanceof TranslatableMessage && '' === $message->getMessage()) {
@@ -108,7 +108,7 @@ public function trans(string|\Stringable|TranslatableInterface|null $message, ar
}
if (!\is_array($arguments)) {
- throw new \TypeError(sprintf('Unless the message is a "%s", argument 2 passed to "%s()" must be an array of parameters, "%s" given.', TranslatableInterface::class, __METHOD__, get_debug_type($arguments)));
+ throw new \TypeError(\sprintf('Unless the message is a "%s", argument 2 passed to "%s()" must be an array of parameters, "%s" given.', TranslatableInterface::class, __METHOD__, get_debug_type($arguments)));
}
if ('' === $message = (string) $message) {
@@ -125,7 +125,7 @@ public function trans(string|\Stringable|TranslatableInterface|null $message, ar
public function createTranslatable(string $message, array $parameters = [], ?string $domain = null): TranslatableMessage
{
if (!class_exists(TranslatableMessage::class)) {
- throw new \LogicException(sprintf('You cannot use the "%s" as the Translation Component is not installed. Try running "composer require symfony/translation".', __CLASS__));
+ throw new \LogicException(\sprintf('You cannot use the "%s" as the Translation Component is not installed. Try running "composer require symfony/translation".', __CLASS__));
}
return new TranslatableMessage($message, $parameters, $domain);
diff --git a/Mime/BodyRenderer.php b/Mime/BodyRenderer.php
index 25d87353..00b7ba00 100644
--- a/Mime/BodyRenderer.php
+++ b/Mime/BodyRenderer.php
@@ -43,7 +43,7 @@ public function render(Message $message): void
return;
}
- if (null === $message->getTextTemplate() && null === $message->getHtmlTemplate()) {
+ if ($message->isRendered()) {
// email has already been rendered
return;
}
@@ -52,7 +52,7 @@ public function render(Message $message): void
$messageContext = $message->getContext();
if (isset($messageContext['email'])) {
- throw new InvalidArgumentException(sprintf('A "%s" context cannot have an "email" entry as this is a reserved variable.', get_debug_type($message)));
+ throw new InvalidArgumentException(\sprintf('A "%s" context cannot have an "email" entry as this is a reserved variable.', get_debug_type($message)));
}
$vars = array_merge($this->context, $messageContext, [
diff --git a/Mime/NotificationEmail.php b/Mime/NotificationEmail.php
index 6e33d33d..4b4e1b26 100644
--- a/Mime/NotificationEmail.php
+++ b/Mime/NotificationEmail.php
@@ -54,7 +54,7 @@ public function __construct(?Headers $headers = null, ?AbstractPart $body = null
}
if ($missingPackages) {
- throw new \LogicException(sprintf('You cannot use "%s" if the "%s" Twig extension%s not available. Try running "%s".', static::class, implode('" and "', $missingPackages), \count($missingPackages) > 1 ? 's are' : ' is', 'composer require '.implode(' ', array_keys($missingPackages))));
+ throw new \LogicException(\sprintf('You cannot use "%s" if the "%s" Twig extension%s not available. Try running "%s".', static::class, implode('" and "', $missingPackages), \count($missingPackages) > 1 ? 's are' : ' is', 'composer require '.implode(' ', array_keys($missingPackages))));
}
parent::__construct($headers, $body);
@@ -88,7 +88,7 @@ public function markAsPublic(): static
public function markdown(string $content): static
{
if (!class_exists(MarkdownExtension::class)) {
- throw new \LogicException(sprintf('You cannot use "%s" if the Markdown Twig extension is not available. Try running "composer require twig/markdown-extra".', __METHOD__));
+ throw new \LogicException(\sprintf('You cannot use "%s" if the Markdown Twig extension is not available. Try running "composer require twig/markdown-extra".', __METHOD__));
}
$this->context['markdown'] = true;
@@ -218,7 +218,7 @@ public function getPreparedHeaders(): Headers
$importance = $this->context['importance'] ?? self::IMPORTANCE_LOW;
$this->priority($this->determinePriority($importance));
if ($this->context['importance']) {
- $headers->setHeaderBody('Text', 'Subject', sprintf('[%s] %s', strtoupper($importance), $this->getSubject()));
+ $headers->setHeaderBody('Text', 'Subject', \sprintf('[%s] %s', strtoupper($importance), $this->getSubject()));
}
return $headers;
diff --git a/Node/DumpNode.php b/Node/DumpNode.php
index 2c474f15..3aaa510a 100644
--- a/Node/DumpNode.php
+++ b/Node/DumpNode.php
@@ -11,7 +11,6 @@
namespace Symfony\Bridge\Twig\Node;
-use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Attribute\YieldReady;
use Twig\Compiler;
use Twig\Node\Expression\Variable\LocalVariable;
@@ -27,20 +26,13 @@ public function __construct(
private LocalVariable|string $varPrefix,
?Node $values,
int $lineno,
- ?string $tag = null,
) {
$nodes = [];
if (null !== $values) {
$nodes['values'] = $values;
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- parent::__construct($nodes, [], $lineno);
- } else {
- parent::__construct($nodes, [], $lineno, $tag);
- }
-
- $this->varPrefix = $varPrefix;
+ parent::__construct($nodes, [], $lineno);
}
public function compile(Compiler $compiler): void
@@ -58,18 +50,18 @@ public function compile(Compiler $compiler): void
if (!$this->hasNode('values')) {
// remove embedded templates (macros) from the context
$compiler
- ->write(sprintf('$%svars = [];'."\n", $varPrefix))
- ->write(sprintf('foreach ($context as $%1$skey => $%1$sval) {'."\n", $varPrefix))
+ ->write(\sprintf('$%svars = [];'."\n", $varPrefix))
+ ->write(\sprintf('foreach ($context as $%1$skey => $%1$sval) {'."\n", $varPrefix))
->indent()
- ->write(sprintf('if (!$%sval instanceof \Twig\Template) {'."\n", $varPrefix))
+ ->write(\sprintf('if (!$%sval instanceof \Twig\Template) {'."\n", $varPrefix))
->indent()
- ->write(sprintf('$%1$svars[$%1$skey] = $%1$sval;'."\n", $varPrefix))
+ ->write(\sprintf('$%1$svars[$%1$skey] = $%1$sval;'."\n", $varPrefix))
->outdent()
->write("}\n")
->outdent()
->write("}\n")
->addDebugInfo($this)
- ->write(sprintf('\Symfony\Component\VarDumper\VarDumper::dump($%svars);'."\n", $varPrefix));
+ ->write(\sprintf('\Symfony\Component\VarDumper\VarDumper::dump($%svars);'."\n", $varPrefix));
} elseif (($values = $this->getNode('values')) && 1 === $values->count()) {
$compiler
->addDebugInfo($this)
diff --git a/Node/FormThemeNode.php b/Node/FormThemeNode.php
index 1d077097..9d9bce1e 100644
--- a/Node/FormThemeNode.php
+++ b/Node/FormThemeNode.php
@@ -12,7 +12,6 @@
namespace Symfony\Bridge\Twig\Node;
use Symfony\Component\Form\FormRenderer;
-use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Attribute\YieldReady;
use Twig\Compiler;
use Twig\Node\Node;
@@ -23,13 +22,19 @@
#[YieldReady]
final class FormThemeNode extends Node
{
- public function __construct(Node $form, Node $resources, int $lineno, ?string $tag = null, bool $only = false)
+ /**
+ * @param bool $only
+ */
+ public function __construct(Node $form, Node $resources, int $lineno, $only = false)
{
- if (class_exists(FirstClassTwigCallableReady::class)) {
- parent::__construct(['form' => $form, 'resources' => $resources], ['only' => $only], $lineno);
- } else {
- parent::__construct(['form' => $form, 'resources' => $resources], ['only' => $only], $lineno, $tag);
+ if (null === $only || \is_string($only)) {
+ trigger_deprecation('symfony/twig-bridge', '3.12', 'Passing a tag to %s() is deprecated.', __METHOD__);
+ $only = \func_num_args() > 4 ? func_get_arg(4) : true;
+ } elseif (!\is_bool($only)) {
+ throw new \TypeError(\sprintf('Argument 4 passed to "%s()" must be a boolean, "%s" given.', __METHOD__, get_debug_type($only)));
}
+
+ parent::__construct(['form' => $form, 'resources' => $resources], ['only' => $only], $lineno);
}
public function compile(Compiler $compiler): void
diff --git a/Node/StopwatchNode.php b/Node/StopwatchNode.php
index e8ac13d6..472b6280 100644
--- a/Node/StopwatchNode.php
+++ b/Node/StopwatchNode.php
@@ -11,7 +11,6 @@
namespace Symfony\Bridge\Twig\Node;
-use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Attribute\YieldReady;
use Twig\Compiler;
use Twig\Node\Expression\AssignNameExpression;
@@ -26,20 +25,9 @@
#[YieldReady]
final class StopwatchNode extends Node
{
- /**
- * @param AssignNameExpression|LocalVariable $var
- */
- public function __construct(Node $name, Node $body, $var, int $lineno = 0, ?string $tag = null)
+ public function __construct(Node $name, Node $body, AssignNameExpression|LocalVariable $var, int $lineno = 0)
{
- if (!$var instanceof AssignNameExpression && !$var instanceof LocalVariable) {
- throw new \TypeError(sprintf('Expected an instance of "%s" or "%s", but got "%s".', AssignNameExpression::class, LocalVariable::class, get_debug_type($var)));
- }
-
- if (class_exists(FirstClassTwigCallableReady::class)) {
- parent::__construct(['body' => $body, 'name' => $name, 'var' => $var], [], $lineno);
- } else {
- parent::__construct(['body' => $body, 'name' => $name, 'var' => $var], [], $lineno, $tag);
- }
+ parent::__construct(['body' => $body, 'name' => $name, 'var' => $var], [], $lineno);
}
public function compile(Compiler $compiler): void
diff --git a/Node/TransDefaultDomainNode.php b/Node/TransDefaultDomainNode.php
index 28cb6f1b..04349839 100644
--- a/Node/TransDefaultDomainNode.php
+++ b/Node/TransDefaultDomainNode.php
@@ -11,7 +11,6 @@
namespace Symfony\Bridge\Twig\Node;
-use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Attribute\YieldReady;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
@@ -23,13 +22,9 @@
#[YieldReady]
final class TransDefaultDomainNode extends Node
{
- public function __construct(AbstractExpression $expr, int $lineno = 0, ?string $tag = null)
+ public function __construct(AbstractExpression $expr, int $lineno = 0)
{
- if (class_exists(FirstClassTwigCallableReady::class)) {
- parent::__construct(['expr' => $expr], [], $lineno);
- } else {
- parent::__construct(['expr' => $expr], [], $lineno, $tag);
- }
+ parent::__construct(['expr' => $expr], [], $lineno);
}
public function compile(Compiler $compiler): void
diff --git a/Node/TransNode.php b/Node/TransNode.php
index a61ee4db..4064491f 100644
--- a/Node/TransNode.php
+++ b/Node/TransNode.php
@@ -11,7 +11,6 @@
namespace Symfony\Bridge\Twig\Node;
-use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Attribute\YieldReady;
use Twig\Compiler;
use Twig\Node\Expression\AbstractExpression;
@@ -28,7 +27,7 @@
#[YieldReady]
final class TransNode extends Node
{
- public function __construct(Node $body, ?Node $domain = null, ?AbstractExpression $count = null, ?AbstractExpression $vars = null, ?AbstractExpression $locale = null, int $lineno = 0, ?string $tag = null)
+ public function __construct(Node $body, ?Node $domain = null, ?AbstractExpression $count = null, ?AbstractExpression $vars = null, ?AbstractExpression $locale = null, int $lineno = 0)
{
$nodes = ['body' => $body];
if (null !== $domain) {
@@ -44,11 +43,7 @@ public function __construct(Node $body, ?Node $domain = null, ?AbstractExpressio
$nodes['locale'] = $locale;
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- parent::__construct($nodes, [], $lineno);
- } else {
- parent::__construct($nodes, [], $lineno, $tag);
- }
+ parent::__construct($nodes, [], $lineno);
}
public function compile(Compiler $compiler): void
diff --git a/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/NodeVisitor/TranslationDefaultDomainNodeVisitor.php
index 8c617550..3b8196fa 100644
--- a/NodeVisitor/TranslationDefaultDomainNodeVisitor.php
+++ b/NodeVisitor/TranslationDefaultDomainNodeVisitor.php
@@ -52,17 +52,25 @@ public function enterNode(Node $node, Environment $env): Node
$this->scope->set('domain', $node->getNode('expr'));
return $node;
- } else {
- $var = $this->getVarName();
- $name = class_exists(AssignContextVariable::class) ? new AssignContextVariable($var, $node->getTemplateLine()) : new AssignNameExpression($var, $node->getTemplateLine());
- $this->scope->set('domain', class_exists(ContextVariable::class) ? new ContextVariable($var, $node->getTemplateLine()) : new NameExpression($var, $node->getTemplateLine()));
-
- if (class_exists(Nodes::class)) {
- return new SetNode(false, new Nodes([$name]), new Nodes([$node->getNode('expr')]), $node->getTemplateLine());
- } else {
- return new SetNode(false, new Node([$name]), new Node([$node->getNode('expr')]), $node->getTemplateLine());
- }
}
+
+ if (null === $templateName = $node->getTemplateName()) {
+ throw new \LogicException('Cannot traverse a node without a template name.');
+ }
+
+ $var = '__internal_trans_default_domain'.hash('xxh128', $templateName);
+
+ if (class_exists(Nodes::class)) {
+ $name = new AssignContextVariable($var, $node->getTemplateLine());
+ $this->scope->set('domain', new ContextVariable($var, $node->getTemplateLine()));
+
+ return new SetNode(false, new Nodes([$name]), new Nodes([$node->getNode('expr')]), $node->getTemplateLine());
+ }
+
+ $name = new AssignNameExpression($var, $node->getTemplateLine());
+ $this->scope->set('domain', new NameExpression($var, $node->getTemplateLine()));
+
+ return new SetNode(false, new Node([$name]), new Node([$node->getNode('expr')]), $node->getTemplateLine());
}
if (!$this->scope->has('domain')) {
@@ -125,9 +133,4 @@ private function isNamedArguments(Node $arguments): bool
return false;
}
-
- private function getVarName(): string
- {
- return sprintf('__internal_%s', hash('xxh128', uniqid(mt_rand(), true)));
- }
}
diff --git a/Resources/views/Email/zurb_2/main.css b/Resources/views/Email/zurb_2/main.css
index dab0df58..7828ce78 100644
--- a/Resources/views/Email/zurb_2/main.css
+++ b/Resources/views/Email/zurb_2/main.css
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2017 ZURB, inc. -- MIT License
*
- * https://github.com/foundation/foundation-emails/blob/v2.2.1/dist/foundation-emails.css
+ * https://github.com/foundation/foundation-emails/blob/v2.4.0/dist/foundation-emails.css
*/
.wrapper {
@@ -34,6 +34,7 @@ body {
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
+.ExternalClass th,
.ExternalClass div {
line-height: 100%;
}
@@ -58,34 +59,33 @@ img {
center {
width: 100%;
- min-width: 580px;
}
a img {
border: none;
}
-p {
- margin: 0 0 0 10px;
- Margin: 0 0 0 10px;
-}
-
table {
border-spacing: 0;
border-collapse: collapse;
}
-td {
+td,
+th {
word-wrap: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
hyphens: auto;
border-collapse: collapse !important;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
}
table,
tr,
-td {
+td,
+th {
padding: 0;
vertical-align: top;
text-align: left;
@@ -140,27 +140,38 @@ th.column {
padding-bottom: 16px;
}
-td.columns .column,
-td.columns .columns,
-td.column .column,
-td.column .columns,
-th.columns .column,
-th.columns .columns,
-th.column .column,
-th.column .columns {
+td.columns .column.first,
+td.columns .columns.first,
+td.column .column.first,
+td.column .columns.first,
+th.columns .column.first,
+th.columns .columns.first,
+th.column .column.first,
+th.column .columns.first {
padding-left: 0 !important;
+}
+
+td.columns .column.last,
+td.columns .columns.last,
+td.column .column.last,
+td.column .columns.last,
+th.columns .column.last,
+th.columns .columns.last,
+th.column .column.last,
+th.column .columns.last {
padding-right: 0 !important;
}
-td.columns .column center,
-td.columns .columns center,
-td.column .column center,
-td.column .columns center,
-th.columns .column center,
-th.columns .columns center,
-th.column .column center,
-th.column .columns center {
- min-width: none !important;
+td.columns .column:not([class*=large-offset]),
+td.columns .columns:not([class*=large-offset]),
+td.column .column:not([class*=large-offset]),
+td.column .columns:not([class*=large-offset]),
+th.columns .column:not([class*=large-offset]),
+th.columns .columns:not([class*=large-offset]),
+th.column .column:not([class*=large-offset]),
+th.column .columns:not([class*=large-offset]) {
+ padding-left: 0 !important;
+ padding-right: 0 !important;
}
td.columns.last,
@@ -170,16 +181,34 @@ th.column.last {
padding-right: 16px;
}
-td.columns table:not(.button),
-td.column table:not(.button),
-th.columns table:not(.button),
-th.column table:not(.button) {
+td.columns table,
+td.column table,
+th.columns table,
+th.column table {
+ width: 100%;
+}
+
+td.columns table.button,
+td.column table.button,
+th.columns table.button,
+th.column table.button {
+ width: auto;
+}
+
+td.columns table.button.expand,
+td.columns table.button.expanded,
+td.column table.button.expand,
+td.column table.button.expanded,
+th.columns table.button.expand,
+th.columns table.button.expanded,
+th.column table.button.expand,
+th.column table.button.expanded {
width: 100%;
}
td.large-1,
th.large-1 {
- width: 32.33333px;
+ width: 32.3333333333px;
padding-left: 8px;
padding-right: 8px;
}
@@ -194,35 +223,30 @@ th.large-1.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-1,
-.collapse>tbody>tr>th.large-1 {
+.collapse>tbody>tr>td.large-1:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-1:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
- width: 48.33333px;
-}
-
-.collapse td.large-1.first,
-.collapse th.large-1.first,
-.collapse td.large-1.last,
-.collapse th.large-1.last {
- width: 56.33333px;
+ width: 48.3333333333px;
}
-td.large-1 center,
-th.large-1 center {
- min-width: 0.33333px;
+.collapse>tbody>tr td.large-1.first,
+.collapse>tbody>tr th.large-1.first,
+.collapse>tbody>tr td.large-1.last,
+.collapse>tbody>tr th.large-1.last {
+ width: 56.3333333333px;
}
.body .columns td.large-1,
.body .column td.large-1,
.body .columns th.large-1,
.body .column th.large-1 {
- width: 8.33333%;
+ width: 8.333333%;
}
td.large-2,
th.large-2 {
- width: 80.66667px;
+ width: 80.6666666667px;
padding-left: 8px;
padding-right: 8px;
}
@@ -237,30 +261,25 @@ th.large-2.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-2,
-.collapse>tbody>tr>th.large-2 {
+.collapse>tbody>tr>td.large-2:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-2:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
- width: 96.66667px;
+ width: 96.6666666667px;
}
-.collapse td.large-2.first,
-.collapse th.large-2.first,
-.collapse td.large-2.last,
-.collapse th.large-2.last {
- width: 104.66667px;
-}
-
-td.large-2 center,
-th.large-2 center {
- min-width: 48.66667px;
+.collapse>tbody>tr td.large-2.first,
+.collapse>tbody>tr th.large-2.first,
+.collapse>tbody>tr td.large-2.last,
+.collapse>tbody>tr th.large-2.last {
+ width: 104.6666666667px;
}
.body .columns td.large-2,
.body .column td.large-2,
.body .columns th.large-2,
.body .column th.large-2 {
- width: 16.66667%;
+ width: 16.666666%;
}
td.large-3,
@@ -280,25 +299,20 @@ th.large-3.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-3,
-.collapse>tbody>tr>th.large-3 {
+.collapse>tbody>tr>td.large-3:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-3:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
width: 145px;
}
-.collapse td.large-3.first,
-.collapse th.large-3.first,
-.collapse td.large-3.last,
-.collapse th.large-3.last {
+.collapse>tbody>tr td.large-3.first,
+.collapse>tbody>tr th.large-3.first,
+.collapse>tbody>tr td.large-3.last,
+.collapse>tbody>tr th.large-3.last {
width: 153px;
}
-td.large-3 center,
-th.large-3 center {
- min-width: 97px;
-}
-
.body .columns td.large-3,
.body .column td.large-3,
.body .columns th.large-3,
@@ -308,7 +322,7 @@ th.large-3 center {
td.large-4,
th.large-4 {
- width: 177.33333px;
+ width: 177.3333333333px;
padding-left: 8px;
padding-right: 8px;
}
@@ -323,35 +337,30 @@ th.large-4.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-4,
-.collapse>tbody>tr>th.large-4 {
+.collapse>tbody>tr>td.large-4:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-4:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
- width: 193.33333px;
-}
-
-.collapse td.large-4.first,
-.collapse th.large-4.first,
-.collapse td.large-4.last,
-.collapse th.large-4.last {
- width: 201.33333px;
+ width: 193.3333333333px;
}
-td.large-4 center,
-th.large-4 center {
- min-width: 145.33333px;
+.collapse>tbody>tr td.large-4.first,
+.collapse>tbody>tr th.large-4.first,
+.collapse>tbody>tr td.large-4.last,
+.collapse>tbody>tr th.large-4.last {
+ width: 201.3333333333px;
}
.body .columns td.large-4,
.body .column td.large-4,
.body .columns th.large-4,
.body .column th.large-4 {
- width: 33.33333%;
+ width: 33.333333%;
}
td.large-5,
th.large-5 {
- width: 225.66667px;
+ width: 225.6666666667px;
padding-left: 8px;
padding-right: 8px;
}
@@ -366,30 +375,25 @@ th.large-5.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-5,
-.collapse>tbody>tr>th.large-5 {
+.collapse>tbody>tr>td.large-5:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-5:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
- width: 241.66667px;
+ width: 241.6666666667px;
}
-.collapse td.large-5.first,
-.collapse th.large-5.first,
-.collapse td.large-5.last,
-.collapse th.large-5.last {
- width: 249.66667px;
-}
-
-td.large-5 center,
-th.large-5 center {
- min-width: 193.66667px;
+.collapse>tbody>tr td.large-5.first,
+.collapse>tbody>tr th.large-5.first,
+.collapse>tbody>tr td.large-5.last,
+.collapse>tbody>tr th.large-5.last {
+ width: 249.6666666667px;
}
.body .columns td.large-5,
.body .column td.large-5,
.body .columns th.large-5,
.body .column th.large-5 {
- width: 41.66667%;
+ width: 41.666666%;
}
td.large-6,
@@ -409,25 +413,20 @@ th.large-6.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-6,
-.collapse>tbody>tr>th.large-6 {
+.collapse>tbody>tr>td.large-6:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-6:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
width: 290px;
}
-.collapse td.large-6.first,
-.collapse th.large-6.first,
-.collapse td.large-6.last,
-.collapse th.large-6.last {
+.collapse>tbody>tr td.large-6.first,
+.collapse>tbody>tr th.large-6.first,
+.collapse>tbody>tr td.large-6.last,
+.collapse>tbody>tr th.large-6.last {
width: 298px;
}
-td.large-6 center,
-th.large-6 center {
- min-width: 242px;
-}
-
.body .columns td.large-6,
.body .column td.large-6,
.body .columns th.large-6,
@@ -437,7 +436,7 @@ th.large-6 center {
td.large-7,
th.large-7 {
- width: 322.33333px;
+ width: 322.3333333333px;
padding-left: 8px;
padding-right: 8px;
}
@@ -452,35 +451,30 @@ th.large-7.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-7,
-.collapse>tbody>tr>th.large-7 {
+.collapse>tbody>tr>td.large-7:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-7:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
- width: 338.33333px;
-}
-
-.collapse td.large-7.first,
-.collapse th.large-7.first,
-.collapse td.large-7.last,
-.collapse th.large-7.last {
- width: 346.33333px;
+ width: 338.3333333333px;
}
-td.large-7 center,
-th.large-7 center {
- min-width: 290.33333px;
+.collapse>tbody>tr td.large-7.first,
+.collapse>tbody>tr th.large-7.first,
+.collapse>tbody>tr td.large-7.last,
+.collapse>tbody>tr th.large-7.last {
+ width: 346.3333333333px;
}
.body .columns td.large-7,
.body .column td.large-7,
.body .columns th.large-7,
.body .column th.large-7 {
- width: 58.33333%;
+ width: 58.333333%;
}
td.large-8,
th.large-8 {
- width: 370.66667px;
+ width: 370.6666666667px;
padding-left: 8px;
padding-right: 8px;
}
@@ -495,30 +489,25 @@ th.large-8.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-8,
-.collapse>tbody>tr>th.large-8 {
+.collapse>tbody>tr>td.large-8:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-8:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
- width: 386.66667px;
-}
-
-.collapse td.large-8.first,
-.collapse th.large-8.first,
-.collapse td.large-8.last,
-.collapse th.large-8.last {
- width: 394.66667px;
+ width: 386.6666666667px;
}
-td.large-8 center,
-th.large-8 center {
- min-width: 338.66667px;
+.collapse>tbody>tr td.large-8.first,
+.collapse>tbody>tr th.large-8.first,
+.collapse>tbody>tr td.large-8.last,
+.collapse>tbody>tr th.large-8.last {
+ width: 394.6666666667px;
}
.body .columns td.large-8,
.body .column td.large-8,
.body .columns th.large-8,
.body .column th.large-8 {
- width: 66.66667%;
+ width: 66.666666%;
}
td.large-9,
@@ -538,25 +527,20 @@ th.large-9.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-9,
-.collapse>tbody>tr>th.large-9 {
+.collapse>tbody>tr>td.large-9:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-9:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
width: 435px;
}
-.collapse td.large-9.first,
-.collapse th.large-9.first,
-.collapse td.large-9.last,
-.collapse th.large-9.last {
+.collapse>tbody>tr td.large-9.first,
+.collapse>tbody>tr th.large-9.first,
+.collapse>tbody>tr td.large-9.last,
+.collapse>tbody>tr th.large-9.last {
width: 443px;
}
-td.large-9 center,
-th.large-9 center {
- min-width: 387px;
-}
-
.body .columns td.large-9,
.body .column td.large-9,
.body .columns th.large-9,
@@ -566,7 +550,7 @@ th.large-9 center {
td.large-10,
th.large-10 {
- width: 467.33333px;
+ width: 467.3333333333px;
padding-left: 8px;
padding-right: 8px;
}
@@ -581,35 +565,30 @@ th.large-10.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-10,
-.collapse>tbody>tr>th.large-10 {
+.collapse>tbody>tr>td.large-10:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-10:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
- width: 483.33333px;
+ width: 483.3333333333px;
}
-.collapse td.large-10.first,
-.collapse th.large-10.first,
-.collapse td.large-10.last,
-.collapse th.large-10.last {
- width: 491.33333px;
-}
-
-td.large-10 center,
-th.large-10 center {
- min-width: 435.33333px;
+.collapse>tbody>tr td.large-10.first,
+.collapse>tbody>tr th.large-10.first,
+.collapse>tbody>tr td.large-10.last,
+.collapse>tbody>tr th.large-10.last {
+ width: 491.3333333333px;
}
.body .columns td.large-10,
.body .column td.large-10,
.body .columns th.large-10,
.body .column th.large-10 {
- width: 83.33333%;
+ width: 83.333333%;
}
td.large-11,
th.large-11 {
- width: 515.66667px;
+ width: 515.6666666667px;
padding-left: 8px;
padding-right: 8px;
}
@@ -624,30 +603,25 @@ th.large-11.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-11,
-.collapse>tbody>tr>th.large-11 {
+.collapse>tbody>tr>td.large-11:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-11:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
- width: 531.66667px;
-}
-
-.collapse td.large-11.first,
-.collapse th.large-11.first,
-.collapse td.large-11.last,
-.collapse th.large-11.last {
- width: 539.66667px;
+ width: 531.6666666667px;
}
-td.large-11 center,
-th.large-11 center {
- min-width: 483.66667px;
+.collapse>tbody>tr td.large-11.first,
+.collapse>tbody>tr th.large-11.first,
+.collapse>tbody>tr td.large-11.last,
+.collapse>tbody>tr th.large-11.last {
+ width: 539.6666666667px;
}
.body .columns td.large-11,
.body .column td.large-11,
.body .columns th.large-11,
.body .column th.large-11 {
- width: 91.66667%;
+ width: 91.666666%;
}
td.large-12,
@@ -667,25 +641,20 @@ th.large-12.last {
padding-right: 16px;
}
-.collapse>tbody>tr>td.large-12,
-.collapse>tbody>tr>th.large-12 {
+.collapse>tbody>tr>td.large-12:not([class*=large-offset]),
+.collapse>tbody>tr>th.large-12:not([class*=large-offset]) {
padding-right: 0;
padding-left: 0;
width: 580px;
}
-.collapse td.large-12.first,
-.collapse th.large-12.first,
-.collapse td.large-12.last,
-.collapse th.large-12.last {
+.collapse>tbody>tr td.large-12.first,
+.collapse>tbody>tr th.large-12.first,
+.collapse>tbody>tr td.large-12.last,
+.collapse>tbody>tr th.large-12.last {
width: 588px;
}
-td.large-12 center,
-th.large-12 center {
- min-width: 532px;
-}
-
.body .columns td.large-12,
.body .column td.large-12,
.body .columns th.large-12,
@@ -699,7 +668,7 @@ td.large-offset-1.last,
th.large-offset-1,
th.large-offset-1.first,
th.large-offset-1.last {
- padding-left: 64.33333px;
+ padding-left: 64.3333333333px;
}
td.large-offset-2,
@@ -708,7 +677,7 @@ td.large-offset-2.last,
th.large-offset-2,
th.large-offset-2.first,
th.large-offset-2.last {
- padding-left: 112.66667px;
+ padding-left: 112.6666666667px;
}
td.large-offset-3,
@@ -726,7 +695,7 @@ td.large-offset-4.last,
th.large-offset-4,
th.large-offset-4.first,
th.large-offset-4.last {
- padding-left: 209.33333px;
+ padding-left: 209.3333333333px;
}
td.large-offset-5,
@@ -735,7 +704,7 @@ td.large-offset-5.last,
th.large-offset-5,
th.large-offset-5.first,
th.large-offset-5.last {
- padding-left: 257.66667px;
+ padding-left: 257.6666666667px;
}
td.large-offset-6,
@@ -753,7 +722,7 @@ td.large-offset-7.last,
th.large-offset-7,
th.large-offset-7.first,
th.large-offset-7.last {
- padding-left: 354.33333px;
+ padding-left: 354.3333333333px;
}
td.large-offset-8,
@@ -762,7 +731,7 @@ td.large-offset-8.last,
th.large-offset-8,
th.large-offset-8.first,
th.large-offset-8.last {
- padding-left: 402.66667px;
+ padding-left: 402.6666666667px;
}
td.large-offset-9,
@@ -780,7 +749,7 @@ td.large-offset-10.last,
th.large-offset-10,
th.large-offset-10.first,
th.large-offset-10.last {
- padding-left: 499.33333px;
+ padding-left: 499.3333333333px;
}
td.large-offset-11,
@@ -789,7 +758,7 @@ td.large-offset-11.last,
th.large-offset-11,
th.large-offset-11.first,
th.large-offset-11.last {
- padding-left: 547.66667px;
+ padding-left: 547.6666666667px;
}
td.expander,
@@ -896,12 +865,15 @@ span.text-center {
float: none !important;
text-align: center !important;
}
+
.small-text-center {
text-align: center !important;
}
+
.small-text-left {
text-align: left !important;
}
+
.small-text-right {
text-align: right !important;
}
@@ -934,8 +906,22 @@ th.float-center {
text-align: center;
}
+td.columns[valign=bottom],
+td.column[valign=bottom],
+th.columns[valign=bottom],
+th.column[valign=bottom] {
+ vertical-align: bottom;
+}
+
+td.columns[valign=middle],
+td.column[valign=middle],
+th.columns[valign=middle],
+th.column[valign=middle] {
+ vertical-align: middle;
+}
+
.hide-for-large {
- display: none !important;
+ display: none;
mso-hide: all;
overflow: hidden;
max-height: 0;
@@ -960,6 +946,7 @@ table.body table.container .hide-for-large * {
}
@media only screen and (max-width: 596px) {
+
table.body table.container .hide-for-large,
table.body table.container .row.hide-for-large {
display: table !important;
@@ -993,8 +980,7 @@ h5,
h6,
p,
td,
-th,
-a {
+th {
color: #0a0a0a;
font-family: Helvetica, Arial, sans-serif;
font-weight: normal;
@@ -1002,7 +988,7 @@ a {
margin: 0;
Margin: 0;
text-align: left;
- line-height: 1.3;
+ line-height: 130%;
}
h1,
@@ -1036,7 +1022,7 @@ h4 {
}
h5 {
- font-size: 20px;
+ font-size: 19px;
}
h6 {
@@ -1049,7 +1035,7 @@ p,
td,
th {
font-size: 16px;
- line-height: 1.3;
+ line-height: 130%;
}
p {
@@ -1059,7 +1045,7 @@ p {
p.lead {
font-size: 20px;
- line-height: 1.6;
+ line-height: 160%;
}
p.subheader {
@@ -1072,7 +1058,33 @@ p.subheader {
color: #8a8a8a;
}
-small {
+p a {
+ margin: default;
+ Margin: default;
+}
+
+.text-xs {
+ font-size: 11.1111111111px;
+}
+
+.text-sm {
+ font-size: 13.3333333333px;
+}
+
+.text-lg {
+ font-size: 19.2px;
+}
+
+.text-xl {
+ font-size: 23.04px;
+}
+
+.text-xxl {
+ font-size: 27.648px;
+}
+
+small,
+.small {
font-size: 80%;
color: #cacaca;
}
@@ -1080,6 +1092,11 @@ small {
a {
color: #2199e8;
text-decoration: none;
+ font-family: Helvetica, Arial, sans-serif;
+ font-weight: normal;
+ padding: 0;
+ text-align: left;
+ line-height: 130%;
}
a:hover {
@@ -1129,20 +1146,42 @@ pre code span.callout-strong {
font-weight: bold;
}
-table.hr {
- width: 100%;
+td.columns table.hr table,
+td.column table.hr table,
+th.columns table.hr table,
+th.column table.hr table,
+td.columns table.h-line table,
+td.column table.h-line table,
+th.columns table.h-line table,
+th.column table.h-line table {
+ width: auto;
+}
+
+table.hr th,
+table.h-line th {
+ padding-bottom: 20px;
+ text-align: center;
}
-table.hr th {
+table.hr table,
+table.h-line table {
+ display: inline-block;
+ margin: 0;
+ Margin: 0;
+}
+
+table.hr th,
+table.h-line th {
+ width: 580px;
height: 0;
- max-width: 580px;
+ padding-top: 20px;
+ clear: both;
border-top: 0;
border-right: 0;
border-bottom: 1px solid #0a0a0a;
border-left: 0;
- margin: 20px auto;
- Margin: 20px auto;
- clear: both;
+ font-size: 0;
+ line-height: 0;
}
.stat {
@@ -1168,6 +1207,17 @@ span.preheader {
overflow: hidden;
}
+@media only screen {
+ a[x-apple-data-detectors] {
+ color: inherit !important;
+ text-decoration: none !important;
+ font-size: inherit !important;
+ font-family: inherit !important;
+ font-weight: inherit !important;
+ line-height: inherit !important;
+ }
+}
+
table.button {
width: auto;
margin: 0 0 16px 0;
@@ -1187,6 +1237,7 @@ table.button table td a {
font-weight: bold;
color: #fefefe;
text-decoration: none;
+ text-align: left;
display: inline-block;
padding: 8px 16px 8px 16px;
border: 0 solid #2199e8;
@@ -1203,6 +1254,10 @@ table.button.rounded table td {
border: none;
}
+table.button:not(.expand):not(.expanded) table {
+ width: auto;
+}
+
table.button:hover table tr td a,
table.button:active table tr td a,
table.button table tr td a:visited,
@@ -1241,7 +1296,7 @@ table.button.large table a {
table.button.expand,
table.button.expanded {
- width: 100% !important;
+ width: 100%;
}
table.button.expand table,
@@ -1372,7 +1427,7 @@ th.callout-inner {
th.callout-inner.primary {
background: #def0fc;
- border: 1px solid #444444;
+ border: 1px solid #0f5f94;
color: #0a0a0a;
}
@@ -1385,19 +1440,19 @@ th.callout-inner.secondary {
th.callout-inner.success {
background: #e1faea;
border: 1px solid #1b9448;
- color: #fefefe;
+ color: #0a0a0a;
}
th.callout-inner.warning {
background: #fff3d9;
border: 1px solid #996800;
- color: #fefefe;
+ color: #0a0a0a;
}
th.callout-inner.alert {
background: #fce6e2;
border: 1px solid #b42912;
- color: #fefefe;
+ color: #0a0a0a;
}
.thumbnail {
@@ -1422,8 +1477,10 @@ table.menu {
table.menu td.menu-item,
table.menu th.menu-item {
- padding: 10px;
+ padding-top: 10px;
padding-right: 10px;
+ padding-bottom: 10px;
+ padding-left: 10px;
}
table.menu td.menu-item a,
@@ -1433,8 +1490,10 @@ table.menu th.menu-item a {
table.menu.vertical td.menu-item,
table.menu.vertical th.menu-item {
- padding: 10px;
+ padding-top: 10px;
padding-right: 0;
+ padding-bottom: 10px;
+ padding-left: 10px;
display: block;
}
@@ -1454,8 +1513,32 @@ table.menu.text-center a {
text-align: center;
}
-.menu[align="center"] {
- width: auto !important;
+.menu[align=center] {
+ width: auto;
+}
+
+.menu[align=center] tr {
+ text-align: center;
+}
+
+.menu:not(.float-center) .menu-item:first-child {
+ padding-left: 0 !important;
+}
+
+.menu:not(.float-center) .menu-item:last-child {
+ padding-right: 0 !important;
+}
+
+.menu.vertical .menu-item {
+ padding-left: 0 !important;
+ padding-right: 0 !important;
+}
+
+@media only screen and (max-width: 596px) {
+ .menu.small-vertical .menu-item {
+ padding-left: 0 !important;
+ padding-right: 0 !important;
+ }
}
body.outlook p {
@@ -1467,12 +1550,15 @@ body.outlook p {
width: auto;
height: auto;
}
+
table.body center {
min-width: 0 !important;
}
+
table.body .container {
width: 95% !important;
}
+
table.body .columns,
table.body .column {
height: auto !important;
@@ -1482,78 +1568,85 @@ body.outlook p {
padding-left: 16px !important;
padding-right: 16px !important;
}
- table.body .columns .column,
- table.body .columns .columns,
- table.body .column .column,
- table.body .column .columns {
- padding-left: 0 !important;
- padding-right: 0 !important;
- }
- table.body .collapse .columns,
- table.body .collapse .column {
+
+ table.body .collapse>tbody>tr>.columns,
+ table.body .collapse>tbody>tr>.column {
padding-left: 0 !important;
padding-right: 0 !important;
}
+
td.small-1,
th.small-1 {
display: inline-block !important;
- width: 8.33333% !important;
+ width: 8.333333% !important;
}
+
td.small-2,
th.small-2 {
display: inline-block !important;
- width: 16.66667% !important;
+ width: 16.666666% !important;
}
+
td.small-3,
th.small-3 {
display: inline-block !important;
width: 25% !important;
}
+
td.small-4,
th.small-4 {
display: inline-block !important;
- width: 33.33333% !important;
+ width: 33.333333% !important;
}
+
td.small-5,
th.small-5 {
display: inline-block !important;
- width: 41.66667% !important;
+ width: 41.666666% !important;
}
+
td.small-6,
th.small-6 {
display: inline-block !important;
width: 50% !important;
}
+
td.small-7,
th.small-7 {
display: inline-block !important;
- width: 58.33333% !important;
+ width: 58.333333% !important;
}
+
td.small-8,
th.small-8 {
display: inline-block !important;
- width: 66.66667% !important;
+ width: 66.666666% !important;
}
+
td.small-9,
th.small-9 {
display: inline-block !important;
width: 75% !important;
}
+
td.small-10,
th.small-10 {
display: inline-block !important;
- width: 83.33333% !important;
+ width: 83.333333% !important;
}
+
td.small-11,
th.small-11 {
display: inline-block !important;
- width: 91.66667% !important;
+ width: 91.666666% !important;
}
+
td.small-12,
th.small-12 {
display: inline-block !important;
width: 100% !important;
}
+
.columns td.small-12,
.column td.small-12,
.columns th.small-12,
@@ -1561,98 +1654,119 @@ body.outlook p {
display: block !important;
width: 100% !important;
}
+
table.body td.small-offset-1,
table.body th.small-offset-1 {
- margin-left: 8.33333% !important;
- Margin-left: 8.33333% !important;
+ margin-left: 8.333333% !important;
+ Margin-left: 8.333333% !important;
}
+
table.body td.small-offset-2,
table.body th.small-offset-2 {
- margin-left: 16.66667% !important;
- Margin-left: 16.66667% !important;
+ margin-left: 16.666666% !important;
+ Margin-left: 16.666666% !important;
}
+
table.body td.small-offset-3,
table.body th.small-offset-3 {
margin-left: 25% !important;
Margin-left: 25% !important;
}
+
table.body td.small-offset-4,
table.body th.small-offset-4 {
- margin-left: 33.33333% !important;
- Margin-left: 33.33333% !important;
+ margin-left: 33.333333% !important;
+ Margin-left: 33.333333% !important;
}
+
table.body td.small-offset-5,
table.body th.small-offset-5 {
- margin-left: 41.66667% !important;
- Margin-left: 41.66667% !important;
+ margin-left: 41.666666% !important;
+ Margin-left: 41.666666% !important;
}
+
table.body td.small-offset-6,
table.body th.small-offset-6 {
margin-left: 50% !important;
Margin-left: 50% !important;
}
+
table.body td.small-offset-7,
table.body th.small-offset-7 {
- margin-left: 58.33333% !important;
- Margin-left: 58.33333% !important;
+ margin-left: 58.333333% !important;
+ Margin-left: 58.333333% !important;
}
+
table.body td.small-offset-8,
table.body th.small-offset-8 {
- margin-left: 66.66667% !important;
- Margin-left: 66.66667% !important;
+ margin-left: 66.666666% !important;
+ Margin-left: 66.666666% !important;
}
+
table.body td.small-offset-9,
table.body th.small-offset-9 {
margin-left: 75% !important;
Margin-left: 75% !important;
}
+
table.body td.small-offset-10,
table.body th.small-offset-10 {
- margin-left: 83.33333% !important;
- Margin-left: 83.33333% !important;
+ margin-left: 83.333333% !important;
+ Margin-left: 83.333333% !important;
}
+
table.body td.small-offset-11,
table.body th.small-offset-11 {
- margin-left: 91.66667% !important;
- Margin-left: 91.66667% !important;
+ margin-left: 91.666666% !important;
+ Margin-left: 91.666666% !important;
}
+
table.body table.columns td.expander,
table.body table.columns th.expander {
display: none !important;
}
+
table.body .right-text-pad,
table.body .text-pad-right {
padding-left: 10px !important;
}
+
table.body .left-text-pad,
table.body .text-pad-left {
padding-right: 10px !important;
}
+
table.menu {
width: 100% !important;
}
+
table.menu td,
table.menu th {
width: auto !important;
display: inline-block !important;
}
+
table.menu.vertical td,
table.menu.vertical th,
table.menu.small-vertical td,
table.menu.small-vertical th {
display: block !important;
}
- table.menu[align="center"] {
+
+ table.menu[align=center] {
width: auto !important;
}
+
table.button.small-expand,
table.button.small-expanded {
width: 100% !important;
}
+
table.button.small-expand table,
table.button.small-expanded table {
width: 100%;
}
+
table.button.small-expand table a,
table.button.small-expanded table a {
text-align: center !important;
@@ -1660,8 +1774,13 @@ body.outlook p {
padding-left: 0 !important;
padding-right: 0 !important;
}
+
table.button.small-expand center,
table.button.small-expanded center {
min-width: 0;
}
-}
+
+ th.callout-inner {
+ padding: 10px !important;
+ }
+}
\ No newline at end of file
diff --git a/Resources/views/Form/form_div_layout.html.twig b/Resources/views/Form/form_div_layout.html.twig
index 1e421d5f..537849fa 100644
--- a/Resources/views/Form/form_div_layout.html.twig
+++ b/Resources/views/Form/form_div_layout.html.twig
@@ -89,7 +89,7 @@
{{- block('choice_widget_options') -}}
{%- else -%}
-
+
{%- endif -%}
{% endfor %}
{%- endblock choice_widget_options -%}
diff --git a/Test/FormLayoutTestCase.php b/Test/FormLayoutTestCase.php
index 1fdd83c9..bd8123a3 100644
--- a/Test/FormLayoutTestCase.php
+++ b/Test/FormLayoutTestCase.php
@@ -19,6 +19,7 @@
use Symfony\Component\Form\Test\FormIntegrationTestCase;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Twig\Environment;
+use Twig\Extension\ExtensionInterface;
use Twig\Loader\FilesystemLoader;
/**
@@ -57,7 +58,7 @@ protected function assertMatchesXpath($html, $expression, $count = 1): void
// the top level
$dom->loadXML(''.$html.'');
} catch (\Exception $e) {
- $this->fail(sprintf(
+ $this->fail(\sprintf(
"Failed loading HTML:\n\n%s\n\nError: %s",
$html,
$e->getMessage()
@@ -68,7 +69,7 @@ protected function assertMatchesXpath($html, $expression, $count = 1): void
if ($nodeList->length != $count) {
$dom->formatOutput = true;
- $this->fail(sprintf(
+ $this->fail(\sprintf(
"Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
$expression,
1 == $count ? 'once' : $count.' times',
@@ -81,15 +82,27 @@ protected function assertMatchesXpath($html, $expression, $count = 1): void
}
}
+ /**
+ * @return string[]
+ */
abstract protected function getTemplatePaths(): array;
+ /**
+ * @return ExtensionInterface[]
+ */
abstract protected function getTwigExtensions(): array;
+ /**
+ * @return array
+ */
protected function getTwigGlobals(): array
{
return [];
}
+ /**
+ * @return string[]
+ */
abstract protected function getThemes(): array;
protected function renderForm(FormView $view, array $vars = []): string
diff --git a/Tests/Command/DebugCommandTest.php b/Tests/Command/DebugCommandTest.php
index 8a67932f..7ba828c6 100644
--- a/Tests/Command/DebugCommandTest.php
+++ b/Tests/Command/DebugCommandTest.php
@@ -314,7 +314,7 @@ public function testComplete(array $input, array $expectedSuggestions)
public static function provideCompletionSuggestions(): iterable
{
yield 'name' => [['email'], []];
- yield 'option --format' => [['--format', ''], ['text', 'json']];
+ yield 'option --format' => [['--format', ''], ['txt', 'json']];
}
private function createCommandTester(array $paths = [], array $bundleMetadata = [], ?string $defaultPath = null, bool $useChainLoader = false, array $globals = []): CommandTester
diff --git a/Tests/EventListener/TemplateAttributeListenerTest.php b/Tests/EventListener/TemplateAttributeListenerTest.php
index e1fb7f95..478f285e 100644
--- a/Tests/EventListener/TemplateAttributeListenerTest.php
+++ b/Tests/EventListener/TemplateAttributeListenerTest.php
@@ -17,10 +17,12 @@
use Symfony\Bridge\Twig\Tests\Fixtures\TemplateAttributeController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Twig\Environment;
+use Twig\Loader\ArrayLoader;
class TemplateAttributeListenerTest extends TestCase
{
@@ -65,6 +67,33 @@ public function testAttribute()
$this->assertSame('Bar', $event->getResponse()->getContent());
}
+ public function testAttributeWithBlock()
+ {
+ $twig = new Environment(new ArrayLoader([
+ 'foo.html.twig' => 'ERROR {% block bar %}FOOBAR{% endblock %}',
+ ]));
+
+ $request = new Request();
+ $kernel = $this->createMock(HttpKernelInterface::class);
+ $controllerArgumentsEvent = new ControllerArgumentsEvent($kernel, [new TemplateAttributeController(), 'foo'], ['Bar'], $request, null);
+ $listener = new TemplateAttributeListener($twig);
+
+ $request->attributes->set('_template', new Template('foo.html.twig', [], false, 'bar'));
+ $event = new ViewEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, ['foo' => 'bar'], $controllerArgumentsEvent);
+ $listener->onKernelView($event);
+ $this->assertSame('FOOBAR', $event->getResponse()->getContent());
+
+ $request->attributes->set('_template', new Template('foo.html.twig', [], true, 'bar'));
+ $event = new ViewEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, ['foo' => 'bar'], $controllerArgumentsEvent);
+ $listener->onKernelView($event);
+ $this->assertInstanceOf(StreamedResponse::class, $event->getResponse());
+
+ $request->attributes->set('_template', new Template('foo.html.twig', [], false, 'not_a_block'));
+ $event = new ViewEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, ['foo' => 'bar'], $controllerArgumentsEvent);
+ $this->expectExceptionMessage('Block "not_a_block" on template "foo.html.twig" does not exist in "foo.html.twig".');
+ $listener->onKernelView($event);
+ }
+
public function testForm()
{
$request = new Request();
diff --git a/Tests/Extension/AbstractBootstrap3HorizontalLayoutTestCase.php b/Tests/Extension/AbstractBootstrap3HorizontalLayoutTestCase.php
index 3a4104bb..db0789db 100644
--- a/Tests/Extension/AbstractBootstrap3HorizontalLayoutTestCase.php
+++ b/Tests/Extension/AbstractBootstrap3HorizontalLayoutTestCase.php
@@ -163,9 +163,9 @@ public function testStartTagWithOverriddenVars()
public function testStartTagForMultipartForm()
{
$form = $this->factory->createBuilder('Symfony\Component\Form\Extension\Core\Type\FormType', null, [
- 'method' => 'get',
- 'action' => 'http://example.com/directory',
- ])
+ 'method' => 'get',
+ 'action' => 'http://example.com/directory',
+ ])
->add('file', 'Symfony\Component\Form\Extension\Core\Type\FileType')
->getForm();
diff --git a/Tests/Extension/AbstractBootstrap4HorizontalLayoutTestCase.php b/Tests/Extension/AbstractBootstrap4HorizontalLayoutTestCase.php
index 723559ee..9b202e92 100644
--- a/Tests/Extension/AbstractBootstrap4HorizontalLayoutTestCase.php
+++ b/Tests/Extension/AbstractBootstrap4HorizontalLayoutTestCase.php
@@ -214,9 +214,9 @@ public function testStartTagWithOverriddenVars()
public function testStartTagForMultipartForm()
{
$form = $this->factory->createBuilder('Symfony\Component\Form\Extension\Core\Type\FormType', null, [
- 'method' => 'get',
- 'action' => 'http://example.com/directory',
- ])
+ 'method' => 'get',
+ 'action' => 'http://example.com/directory',
+ ])
->add('file', 'Symfony\Component\Form\Extension\Core\Type\FileType')
->getForm();
diff --git a/Tests/Extension/AbstractDivLayoutTestCase.php b/Tests/Extension/AbstractDivLayoutTestCase.php
index a02fca4b..28e8997a 100644
--- a/Tests/Extension/AbstractDivLayoutTestCase.php
+++ b/Tests/Extension/AbstractDivLayoutTestCase.php
@@ -619,6 +619,13 @@ public function testThemeBlockInheritance($theme)
);
}
+ public static function themeBlockInheritanceProvider(): array
+ {
+ return [
+ [['theme.html.twig']],
+ ];
+ }
+
/**
* @dataProvider themeInheritanceProvider
*/
@@ -663,6 +670,13 @@ public function testThemeInheritance($parentTheme, $childTheme)
);
}
+ public static function themeInheritanceProvider(): array
+ {
+ return [
+ [['parent_label.html.twig'], ['child_label.html.twig']],
+ ];
+ }
+
/**
* The block "_name_child_label" should be overridden in the theme of the
* implemented driver.
@@ -691,9 +705,9 @@ public function testCollectionRowWithCustomBlock()
public function testChoiceRowWithCustomBlock()
{
$form = $this->factory->createNamedBuilder('name_c', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', 'a', [
- 'choices' => ['ChoiceA' => 'a', 'ChoiceB' => 'b'],
- 'expanded' => true,
- ])
+ 'choices' => ['ChoiceA' => 'a', 'ChoiceB' => 'b'],
+ 'expanded' => true,
+ ])
->getForm();
$this->assertWidgetMatchesXpath($form->createView(), [],
@@ -856,6 +870,56 @@ public function testMultipleChoiceExpandedWithLabelsSetFalseByCallable()
);
}
+ public function testSingleChoiceWithoutDuplicatePreferredIsSelected()
+ {
+ $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&d', [
+ 'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c', 'Choice&D' => '&d'],
+ 'preferred_choices' => ['&b', '&d'],
+ 'duplicate_preferred_choices' => false,
+ 'multiple' => false,
+ 'expanded' => false,
+ ]);
+
+ $this->assertWidgetMatchesXpath($form->createView(), ['separator' => '-- sep --'],
+ '/select
+ [@name="name"]
+ [
+ ./option[@value="&d"][@selected="selected"]
+ /following-sibling::option[@disabled="disabled"][.="-- sep --"]
+ /following-sibling::option[@value="&a"][not(@selected)]
+ /following-sibling::option[@value="&c"][not(@selected)]
+ ]
+ [count(./option)=5]
+'
+ );
+ }
+
+ public function testSingleChoiceWithoutDuplicateNotPreferredIsSelected()
+ {
+ $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&d', [
+ 'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c', 'Choice&D' => '&d'],
+ 'preferred_choices' => ['&b', '&d'],
+ 'duplicate_preferred_choices' => true,
+ 'multiple' => false,
+ 'expanded' => false,
+ ]);
+
+ $this->assertWidgetMatchesXpath($form->createView(), ['separator' => '-- sep --'],
+ '/select
+ [@name="name"]
+ [
+ ./option[@value="&d"][not(@selected)]
+ /following-sibling::option[@disabled="disabled"][.="-- sep --"]
+ /following-sibling::option[@value="&a"][not(@selected)]
+ /following-sibling::option[@value="&b"][not(@selected)]
+ /following-sibling::option[@value="&c"][not(@selected)]
+ /following-sibling::option[@value="&d"][@selected="selected"]
+ ]
+ [count(./option)=7]
+'
+ );
+ }
+
public function testFormEndWithRest()
{
$view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
diff --git a/Tests/Extension/AbstractLayoutTestCase.php b/Tests/Extension/AbstractLayoutTestCase.php
index 4c620213..5a541d7b 100644
--- a/Tests/Extension/AbstractLayoutTestCase.php
+++ b/Tests/Extension/AbstractLayoutTestCase.php
@@ -17,6 +17,7 @@
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
use Symfony\Component\Form\FormError;
+use Symfony\Component\Form\FormExtensionInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Translation\TranslatableMessage;
@@ -44,7 +45,10 @@ protected function setUp(): void
parent::setUp();
}
- protected function getExtensions()
+ /**
+ * @return FormExtensionInterface[]
+ */
+ protected function getExtensions(): array
{
return [
new CsrfExtension($this->csrfTokenManager),
@@ -54,8 +58,6 @@ protected function getExtensions()
protected function tearDown(): void
{
\Locale::setDefault($this->defaultLocale);
-
- parent::tearDown();
}
protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
@@ -310,8 +312,8 @@ public function testLabelFormatOverriddenOption()
public function testLabelWithoutTranslationOnButton()
{
$form = $this->factory->createNamedBuilder('myform', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, [
- 'translation_domain' => false,
- ])
+ 'translation_domain' => false,
+ ])
->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType')
->getForm();
$view = $form->get('mybutton')->createView();
@@ -2393,9 +2395,9 @@ public function testStartTagWithOverriddenVars()
public function testStartTagForMultipartForm()
{
$form = $this->factory->createBuilder('Symfony\Component\Form\Extension\Core\Type\FormType', null, [
- 'method' => 'get',
- 'action' => 'http://example.com/directory',
- ])
+ 'method' => 'get',
+ 'action' => 'http://example.com/directory',
+ ])
->add('file', 'Symfony\Component\Form\Extension\Core\Type\FileType')
->getForm();
@@ -2540,8 +2542,8 @@ public function testTranslatedAttributes()
public function testAttributesNotTranslatedWhenTranslationDomainIsFalse()
{
$view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, [
- 'translation_domain' => false,
- ])
+ 'translation_domain' => false,
+ ])
->add('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', ['attr' => ['title' => 'Foo']])
->add('lastName', 'Symfony\Component\Form\Extension\Core\Type\TextType', ['attr' => ['placeholder' => 'Bar']])
->getForm()
@@ -2648,7 +2650,7 @@ public function testHelpWithTranslatableMessage()
public function testHelpWithTranslatableInterface()
{
- $message = new class() implements TranslatableInterface {
+ $message = new class implements TranslatableInterface {
public function trans(TranslatorInterface $translator, ?string $locale = null): string
{
return $translator->trans('foo');
diff --git a/Tests/Extension/FormExtensionDivLayoutTest.php b/Tests/Extension/FormExtensionDivLayoutTest.php
index ad2627a2..d0e90b1f 100644
--- a/Tests/Extension/FormExtensionDivLayoutTest.php
+++ b/Tests/Extension/FormExtensionDivLayoutTest.php
@@ -349,20 +349,6 @@ protected function setTheme(FormView $view, array $themes, $useDefaultThemes = t
$this->renderer->setTheme($view, $themes, $useDefaultThemes);
}
- public static function themeBlockInheritanceProvider(): array
- {
- return [
- [['theme.html.twig']],
- ];
- }
-
- public static function themeInheritanceProvider(): array
- {
- return [
- [['parent_label.html.twig'], ['child_label.html.twig']],
- ];
- }
-
protected function getTemplatePaths(): array
{
return [
diff --git a/Tests/Extension/FormExtensionFieldHelpersTest.php b/Tests/Extension/FormExtensionFieldHelpersTest.php
index b65b53a0..efedc871 100644
--- a/Tests/Extension/FormExtensionFieldHelpersTest.php
+++ b/Tests/Extension/FormExtensionFieldHelpersTest.php
@@ -27,7 +27,7 @@ class FormExtensionFieldHelpersTest extends FormIntegrationTestCase
private FormExtension $translatorExtension;
private FormView $view;
- protected function getTypes()
+ protected function getTypes(): array
{
return [new TextType(), new ChoiceType()];
}
diff --git a/Tests/Extension/HttpKernelExtensionTest.php b/Tests/Extension/HttpKernelExtensionTest.php
index 36530182..ccce1de3 100644
--- a/Tests/Extension/HttpKernelExtensionTest.php
+++ b/Tests/Extension/HttpKernelExtensionTest.php
@@ -67,7 +67,7 @@ public function testGenerateFragmentUri()
$kernelRuntime = new HttpKernelRuntime($fragmentHandler, $fragmentUriGenerator);
$loader = new ArrayLoader([
- 'index' => sprintf(<< \sprintf(<<textTemplate('text');
+ $this->assertFalse($email->isRendered());
$renderer->render($email);
+ $this->assertTrue($email->isRendered());
+
$this->assertEquals('Text', $email->getTextBody());
$email->text('reset');
+ $this->assertTrue($email->isRendered());
$renderer->render($email);
$this->assertEquals('reset', $email->getTextBody());
diff --git a/Tests/Node/FormThemeTest.php b/Tests/Node/FormThemeTest.php
index e0bb3d55..f98b93da 100644
--- a/Tests/Node/FormThemeTest.php
+++ b/Tests/Node/FormThemeTest.php
@@ -70,17 +70,17 @@ public function testCompile()
$compiler = new Compiler($environment);
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime("Symfony\\\\Component\\\\Form\\\\FormRenderer")->setTheme(%s, [1 => "tpl1", 0 => "tpl2"], true);',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
- $node = new FormThemeNode($form, $resources, 0, null, true);
+ $node = new FormThemeNode($form, $resources, 0, true);
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime("Symfony\\\\Component\\\\Form\\\\FormRenderer")->setTheme(%s, [1 => "tpl1", 0 => "tpl2"], false);',
$this->getVariableGetter('form')
),
@@ -92,17 +92,17 @@ public function testCompile()
$node = new FormThemeNode($form, $resources, 0);
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime("Symfony\\\\Component\\\\Form\\\\FormRenderer")->setTheme(%s, "tpl1", true);',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
- $node = new FormThemeNode($form, $resources, 0, null, true);
+ $node = new FormThemeNode($form, $resources, 0, true);
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime("Symfony\\\\Component\\\\Form\\\\FormRenderer")->setTheme(%s, "tpl1", false);',
$this->getVariableGetter('form')
),
@@ -112,6 +112,6 @@ public function testCompile()
protected function getVariableGetter($name)
{
- return sprintf('($context["%s"] ?? null)', $name);
+ return \sprintf('($context["%s"] ?? null)', $name);
}
}
diff --git a/Tests/Node/SearchAndRenderBlockNodeTest.php b/Tests/Node/SearchAndRenderBlockNodeTest.php
index 47ec58ac..ab9113ac 100644
--- a/Tests/Node/SearchAndRenderBlockNodeTest.php
+++ b/Tests/Node/SearchAndRenderBlockNodeTest.php
@@ -13,7 +13,6 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode;
-use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Compiler;
use Twig\Environment;
use Twig\Extension\CoreExtension;
@@ -42,16 +41,12 @@ public function testCompileWidget()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_widget'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_widget', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_widget'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'widget\')',
$this->getVariableGetter('form')
),
@@ -79,16 +74,12 @@ public function testCompileWidgetWithVariables()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_widget'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_widget', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_widget'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'widget\', ["foo" => "bar"])',
$this->getVariableGetter('form')
),
@@ -110,16 +101,12 @@ public function testCompileLabelWithLabel()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\', ["label" => "my label"])',
$this->getVariableGetter('form')
),
@@ -141,18 +128,14 @@ public function testCompileLabelWithNullLabel()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
// "label" => null must not be included in the output!
// Otherwise the default label is overwritten with null.
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\')',
$this->getVariableGetter('form')
),
@@ -174,18 +157,14 @@ public function testCompileLabelWithEmptyStringLabel()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
// "label" => null must not be included in the output!
// Otherwise the default label is overwritten with null.
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\')',
$this->getVariableGetter('form')
),
@@ -205,16 +184,12 @@ public function testCompileLabelWithDefaultLabel()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\')',
$this->getVariableGetter('form')
),
@@ -244,11 +219,7 @@ public function testCompileLabelWithAttributes()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
@@ -256,7 +227,7 @@ public function testCompileLabelWithAttributes()
// Otherwise the default label is overwritten with null.
// https://github.com/symfony/symfony/issues/5029
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\', ["foo" => "bar"])',
$this->getVariableGetter('form')
),
@@ -290,16 +261,12 @@ public function testCompileLabelWithLabelAndAttributes()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\', ["foo" => "bar", "label" => "value in argument"])',
$this->getVariableGetter('form')
),
@@ -337,11 +304,7 @@ public function testCompileLabelWithLabelThatEvaluatesToNull()
$arguments = new Node([new NameExpression('form', 0), $conditional]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
@@ -349,7 +312,7 @@ public function testCompileLabelWithLabelThatEvaluatesToNull()
// Otherwise the default label is overwritten with null.
// https://github.com/symfony/symfony/issues/5029
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\', (%s($_label_ = ((true) ? (null) : (null))) ? [] : ["label" => $_label_]))',
$this->getVariableGetter('form'),
method_exists(CoreExtension::class, 'testEmpty') ? 'CoreExtension::testEmpty' : 'twig_test_empty'
@@ -406,11 +369,7 @@ public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
- } else {
- $node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
- }
+ $node = new SearchAndRenderBlockNode(new TwigFunction('form_label'), $arguments, 0);
$compiler = new Compiler(new Environment($this->createMock(LoaderInterface::class)));
@@ -418,7 +377,7 @@ public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes()
// Otherwise the default label is overwritten with null.
// https://github.com/symfony/symfony/issues/5029
$this->assertEquals(
- sprintf(
+ \sprintf(
'$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\', ["foo" => "bar", "label" => "value in attributes"] + (%s($_label_ = ((true) ? (null) : (null))) ? [] : ["label" => $_label_]))',
$this->getVariableGetter('form'),
method_exists(CoreExtension::class, 'testEmpty') ? 'CoreExtension::testEmpty' : 'twig_test_empty'
@@ -429,6 +388,6 @@ public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes()
protected function getVariableGetter($name)
{
- return sprintf('($context["%s"] ?? null)', $name);
+ return \sprintf('($context["%s"] ?? null)', $name);
}
}
diff --git a/Tests/Node/TransNodeTest.php b/Tests/Node/TransNodeTest.php
index c5542ea0..24fa4d25 100644
--- a/Tests/Node/TransNodeTest.php
+++ b/Tests/Node/TransNodeTest.php
@@ -35,7 +35,7 @@ public function testCompileStrict()
$compiler = new Compiler($env);
$this->assertEquals(
- sprintf(
+ \sprintf(
'yield $this->env->getExtension(\'Symfony\Bridge\Twig\Extension\TranslationExtension\')->trans("trans %%var%%", array_merge(["%%var%%" => %s], %s), "messages");',
$this->getVariableGetterWithoutStrictCheck('var'),
$this->getVariableGetterWithStrictCheck('foo')
@@ -46,11 +46,11 @@ public function testCompileStrict()
protected function getVariableGetterWithoutStrictCheck($name)
{
- return sprintf('($context["%s"] ?? null)', $name);
+ return \sprintf('($context["%s"] ?? null)', $name);
}
protected function getVariableGetterWithStrictCheck($name)
{
- return sprintf('(isset($context["%1$s"]) || array_key_exists("%1$s", $context) ? $context["%1$s"] : (function () { throw new RuntimeError(\'Variable "%1$s" does not exist.\', 0, $this->source); })())', $name);
+ return \sprintf('(isset($context["%1$s"]) || array_key_exists("%1$s", $context) ? $context["%1$s"] : (function () { throw new RuntimeError(\'Variable "%1$s" does not exist.\', 0, $this->source); })())', $name);
}
}
diff --git a/Tests/NodeVisitor/TranslationNodeVisitorTest.php b/Tests/NodeVisitor/TranslationNodeVisitorTest.php
index 6dbd0d27..2d52c4ea 100644
--- a/Tests/NodeVisitor/TranslationNodeVisitorTest.php
+++ b/Tests/NodeVisitor/TranslationNodeVisitorTest.php
@@ -13,7 +13,6 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
-use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Environment;
use Twig\Loader\LoaderInterface;
use Twig\Node\Expression\ArrayExpression;
@@ -54,21 +53,12 @@ public function testMessageExtractionWithInvalidDomainNode()
]);
}
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $node = new FilterExpression(
- new ConstantExpression($message, 0),
- new TwigFilter('trans'),
- $n,
- 0
- );
- } else {
- $node = new FilterExpression(
- new ConstantExpression($message, 0),
- new ConstantExpression('trans', 0),
- $n,
- 0
- );
- }
+ $node = new FilterExpression(
+ new ConstantExpression($message, 0),
+ new TwigFilter('trans'),
+ $n,
+ 0
+ );
$this->testMessagesExtraction($node, [[$message, TranslationNodeVisitor::UNDEFINED_DOMAIN]]);
}
diff --git a/Tests/NodeVisitor/TwigNodeProvider.php b/Tests/NodeVisitor/TwigNodeProvider.php
index 69cf6bec..64ce92bc 100644
--- a/Tests/NodeVisitor/TwigNodeProvider.php
+++ b/Tests/NodeVisitor/TwigNodeProvider.php
@@ -13,8 +13,8 @@
use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
use Symfony\Bridge\Twig\Node\TransNode;
-use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Node\BodyNode;
+use Twig\Node\EmptyNode;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
@@ -28,13 +28,15 @@ class TwigNodeProvider
{
public static function getModule($content)
{
+ $emptyNodeExists = class_exists(EmptyNode::class);
+
return new ModuleNode(
new BodyNode([new ConstantExpression($content, 0)]),
null,
- new ArrayExpression([], 0),
- new ArrayExpression([], 0),
- new ArrayExpression([], 0),
- null,
+ $emptyNodeExists ? new EmptyNode() : new ArrayExpression([], 0),
+ $emptyNodeExists ? new EmptyNode() : new ArrayExpression([], 0),
+ $emptyNodeExists ? new EmptyNode() : new ArrayExpression([], 0),
+ $emptyNodeExists ? new EmptyNode() : null,
new Source('', '')
);
}
@@ -54,15 +56,6 @@ public static function getTransFilter($message, $domain = null, $arguments = nul
$args = new Node($arguments);
}
- if (!class_exists(FirstClassTwigCallableReady::class)) {
- return new FilterExpression(
- new ConstantExpression($message, 0),
- new ConstantExpression('trans', 0),
- $args,
- 0
- );
- }
-
return new FilterExpression(
new ConstantExpression($message, 0),
new TwigFilter('trans'),
diff --git a/Tests/TokenParser/FormThemeTokenParserTest.php b/Tests/TokenParser/FormThemeTokenParserTest.php
index 02b6597c..4e8209ef 100644
--- a/Tests/TokenParser/FormThemeTokenParserTest.php
+++ b/Tests/TokenParser/FormThemeTokenParserTest.php
@@ -14,7 +14,6 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Node\FormThemeNode;
use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
-use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Environment;
use Twig\Loader\LoaderInterface;
use Twig\Node\Expression\ArrayExpression;
@@ -37,10 +36,7 @@ public function testCompile($source, $expected)
$stream = $env->tokenize($source);
$parser = new Parser($env);
- if (class_exists(FirstClassTwigCallableReady::class)) {
- $expected->setNodeTag('form_theme');
- }
-
+ $expected->setNodeTag('form_theme');
$expected->setSourceContext($source);
$this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0));
@@ -57,8 +53,7 @@ class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new Name
new ConstantExpression(0, 1),
new ConstantExpression('tpl1', 1),
], 1),
- 1,
- 'form_theme'
+ 1
),
],
[
@@ -71,8 +66,7 @@ class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new Name
new ConstantExpression(1, 1),
new ConstantExpression('tpl2', 1),
], 1),
- 1,
- 'form_theme'
+ 1
),
],
[
@@ -80,8 +74,7 @@ class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new Name
new FormThemeNode(
class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new NameExpression('form', 1),
new ConstantExpression('tpl1', 1),
- 1,
- 'form_theme'
+ 1
),
],
[
@@ -92,8 +85,7 @@ class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new Name
new ConstantExpression(0, 1),
new ConstantExpression('tpl1', 1),
], 1),
- 1,
- 'form_theme'
+ 1
),
],
[
@@ -106,8 +98,7 @@ class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new Name
new ConstantExpression(1, 1),
new ConstantExpression('tpl2', 1),
], 1),
- 1,
- 'form_theme'
+ 1
),
],
[
@@ -121,7 +112,6 @@ class_exists(ContextVariable::class) ? new ContextVariable('form', 1) : new Name
new ConstantExpression('tpl2', 1),
], 1),
1,
- 'form_theme',
true
),
],
diff --git a/TokenParser/DumpTokenParser.php b/TokenParser/DumpTokenParser.php
index e671f9ba..9c12dc23 100644
--- a/TokenParser/DumpTokenParser.php
+++ b/TokenParser/DumpTokenParser.php
@@ -14,6 +14,7 @@
use Symfony\Bridge\Twig\Node\DumpNode;
use Twig\Node\Expression\Variable\LocalVariable;
use Twig\Node\Node;
+use Twig\Node\Nodes;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
@@ -34,13 +35,28 @@ public function parse(Token $token): Node
{
$values = null;
if (!$this->parser->getStream()->test(Token::BLOCK_END_TYPE)) {
- $values = $this->parser->getExpressionParser()->parseMultitargetExpression();
+ $values = method_exists($this->parser, 'parseExpression') ?
+ $this->parseMultitargetExpression() :
+ $this->parser->getExpressionParser()->parseMultitargetExpression();
}
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
return new DumpNode(class_exists(LocalVariable::class) ? new LocalVariable(null, $token->getLine()) : $this->parser->getVarName(), $values, $token->getLine(), $this->getTag());
}
+ private function parseMultitargetExpression(): Node
+ {
+ $targets = [];
+ while (true) {
+ $targets[] = $this->parser->parseExpression();
+ if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ',')) {
+ break;
+ }
+ }
+
+ return new Nodes($targets);
+ }
+
public function getTag(): string
{
return 'dump';
diff --git a/TokenParser/FormThemeTokenParser.php b/TokenParser/FormThemeTokenParser.php
index b95a2a05..0988eae5 100644
--- a/TokenParser/FormThemeTokenParser.php
+++ b/TokenParser/FormThemeTokenParser.php
@@ -29,12 +29,16 @@ public function parse(Token $token): Node
$lineno = $token->getLine();
$stream = $this->parser->getStream();
- $form = $this->parser->getExpressionParser()->parseExpression();
+ $parseExpression = method_exists($this->parser, 'parseExpression')
+ ? $this->parser->parseExpression(...)
+ : $this->parser->getExpressionParser()->parseExpression(...);
+
+ $form = $parseExpression();
$only = false;
if ($this->parser->getStream()->test(Token::NAME_TYPE, 'with')) {
$this->parser->getStream()->next();
- $resources = $this->parser->getExpressionParser()->parseExpression();
+ $resources = $parseExpression();
if ($this->parser->getStream()->nextIf(Token::NAME_TYPE, 'only')) {
$only = true;
@@ -42,13 +46,13 @@ public function parse(Token $token): Node
} else {
$resources = new ArrayExpression([], $stream->getCurrent()->getLine());
do {
- $resources->addElement($this->parser->getExpressionParser()->parseExpression());
+ $resources->addElement($parseExpression());
} while (!$stream->test(Token::BLOCK_END_TYPE));
}
$stream->expect(Token::BLOCK_END_TYPE);
- return new FormThemeNode($form, $resources, $lineno, $this->getTag(), $only);
+ return new FormThemeNode($form, $resources, $lineno, $only);
}
public function getTag(): string
diff --git a/TokenParser/StopwatchTokenParser.php b/TokenParser/StopwatchTokenParser.php
index ac6baa6d..d77cbbf4 100644
--- a/TokenParser/StopwatchTokenParser.php
+++ b/TokenParser/StopwatchTokenParser.php
@@ -36,7 +36,9 @@ public function parse(Token $token): Node
$stream = $this->parser->getStream();
// {% stopwatch 'bar' %}
- $name = $this->parser->getExpressionParser()->parseExpression();
+ $name = method_exists($this->parser, 'parseExpression') ?
+ $this->parser->parseExpression() :
+ $this->parser->getExpressionParser()->parseExpression();
$stream->expect(Token::BLOCK_END_TYPE);
diff --git a/TokenParser/TransDefaultDomainTokenParser.php b/TokenParser/TransDefaultDomainTokenParser.php
index c6d850d0..a64a2332 100644
--- a/TokenParser/TransDefaultDomainTokenParser.php
+++ b/TokenParser/TransDefaultDomainTokenParser.php
@@ -25,7 +25,9 @@ final class TransDefaultDomainTokenParser extends AbstractTokenParser
{
public function parse(Token $token): Node
{
- $expr = $this->parser->getExpressionParser()->parseExpression();
+ $expr = method_exists($this->parser, 'parseExpression') ?
+ $this->parser->parseExpression() :
+ $this->parser->getExpressionParser()->parseExpression();
$this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
diff --git a/TokenParser/TransTokenParser.php b/TokenParser/TransTokenParser.php
index e60263a4..f522356b 100644
--- a/TokenParser/TransTokenParser.php
+++ b/TokenParser/TransTokenParser.php
@@ -36,29 +36,33 @@ public function parse(Token $token): Node
$vars = new ArrayExpression([], $lineno);
$domain = null;
$locale = null;
+ $parseExpression = method_exists($this->parser, 'parseExpression')
+ ? $this->parser->parseExpression(...)
+ : $this->parser->getExpressionParser()->parseExpression(...);
+
if (!$stream->test(Token::BLOCK_END_TYPE)) {
if ($stream->test('count')) {
// {% trans count 5 %}
$stream->next();
- $count = $this->parser->getExpressionParser()->parseExpression();
+ $count = $parseExpression();
}
if ($stream->test('with')) {
// {% trans with vars %}
$stream->next();
- $vars = $this->parser->getExpressionParser()->parseExpression();
+ $vars = $parseExpression();
}
if ($stream->test('from')) {
// {% trans from "messages" %}
$stream->next();
- $domain = $this->parser->getExpressionParser()->parseExpression();
+ $domain = $parseExpression();
}
if ($stream->test('into')) {
// {% trans into "fr" %}
$stream->next();
- $locale = $this->parser->getExpressionParser()->parseExpression();
+ $locale = $parseExpression();
} elseif (!$stream->test(Token::BLOCK_END_TYPE)) {
throw new SyntaxError('Unexpected token. Twig was looking for the "with", "from", or "into" keyword.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
}
@@ -74,7 +78,7 @@ public function parse(Token $token): Node
$stream->expect(Token::BLOCK_END_TYPE);
- return new TransNode($body, $domain, $count, $vars, $locale, $lineno, $this->getTag());
+ return new TransNode($body, $domain, $count, $vars, $locale, $lineno);
}
public function decideTransFork(Token $token): bool
diff --git a/UndefinedCallableHandler.php b/UndefinedCallableHandler.php
index b9438be5..5da9a148 100644
--- a/UndefinedCallableHandler.php
+++ b/UndefinedCallableHandler.php
@@ -115,7 +115,7 @@ public static function onUndefinedFunction(string $name): TwigFunction|false
private static function onUndefined(string $name, string $type, string $component): string
{
if (class_exists(FullStack::class) && isset(self::FULL_STACK_ENABLE[$component])) {
- return sprintf('Did you forget to %s? Unknown %s "%s".', self::FULL_STACK_ENABLE[$component], $type, $name);
+ return \sprintf('Did you forget to %s? Unknown %s "%s".', self::FULL_STACK_ENABLE[$component], $type, $name);
}
$missingPackage = 'symfony/'.$component;
@@ -124,6 +124,6 @@ private static function onUndefined(string $name, string $type, string $componen
$missingPackage = 'symfony/twig-bundle';
}
- return sprintf('Did you forget to run "composer require %s"? Unknown %s "%s".', $missingPackage, $type, $name);
+ return \sprintf('Did you forget to run "composer require %s"? Unknown %s "%s".', $missingPackage, $type, $name);
}
}
diff --git a/composer.json b/composer.json
index f7f8d32d..f0ae491d 100644
--- a/composer.json
+++ b/composer.json
@@ -17,8 +17,9 @@
],
"require": {
"php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/translation-contracts": "^2.5|^3",
- "twig/twig": "^3.9"
+ "twig/twig": "^3.12"
},
"require-dev": {
"egulias/email-validator": "^2.1.10|^3|^4",
@@ -29,7 +30,7 @@
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/emoji": "^7.1",
"symfony/finder": "^6.4|^7.0",
- "symfony/form": "^6.4|^7.0",
+ "symfony/form": "^6.4.20|^7.2.5",
"symfony/html-sanitizer": "^6.4|^7.0",
"symfony/http-foundation": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",