Skip to content

[DoctrineBridge] Fix bug with date immutable and datetime immutable #39469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 107 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
6ad0169
[Intl] deprecate polyfills in favor of symfony/polyfill-intl-icu
nicolas-grekas Nov 3, 2020
b285584
updated version to 5.3
fabpot Nov 10, 2020
7e3855d
feature #38974 [Intl] deprecate polyfills in favor of symfony/polyfil…
nicolas-grekas Nov 11, 2020
f0ff411
Merge branch '5.2' into 5.x
nicolas-grekas Nov 11, 2020
66edc59
[Messenger][SQS] Make sure one can enable debug logs
Nyholm Nov 5, 2020
1d945b9
feature #38998 [Messenger][SQS] Make sure one can enable debug logs (…
chalasr Nov 11, 2020
c2fa2cb
[BrowserKit] Add jsonRequest function to the browser-kit client
alexander-schranz Oct 16, 2020
16fb94b
feature #38596 [BrowserKit] Add jsonRequest function to the browser-k…
chalasr Nov 11, 2020
9e5fefa
Merge branch '5.2' into 5.x
jderusse Nov 12, 2020
430b916
Merge branch '5.2' into 5.x
derrabus Nov 12, 2020
c82c997
Merge branch '5.2' into 5.x
xabbuh Nov 13, 2020
281af26
[Messenger] Make all the dependencies of AmazonSqsTransport injectable
jacekwilczynski Oct 26, 2020
b77ef9f
feature #38846 [Messenger] Make all the dependencies of AmazonSqsTran…
derrabus Nov 15, 2020
2a453c2
Merge branch '5.2' into 5.x
derrabus Nov 15, 2020
46a8007
[Messenger] Allow InMemoryTransport to serialize message
tyx Nov 13, 2020
2fa9291
Merge branch '5.2' into 5.x
derrabus Nov 16, 2020
d3b9440
[Ldap] Ldap Entry case-sensitive attribute key option
karlshea Nov 8, 2020
3c0cfbc
Merge branch '5.2' into 5.x
derrabus Nov 18, 2020
f0bbdc8
[Console][Yaml] Linter: add Github annotations format for errors
ogizanagi Nov 3, 2020
04eec8b
feature #38982 [Console][Yaml] Linter: add Github annotations format …
chalasr Nov 20, 2020
a273b71
feature #39075 [Messenger]  Allow InMemoryTransport to serialize mess…
chalasr Nov 20, 2020
49eafee
Merge branch '5.2' into 5.x
xabbuh Nov 21, 2020
449147b
Added Invalid constant into Command Class
TheGarious Nov 23, 2020
a07b722
Merge branch '5.2' into 5.x
derrabus Nov 27, 2020
4346ef4
feature #39146 [Console] Added Invalid constant into Command Class (T…
fabpot Nov 27, 2020
a4b2bf8
feature #39037 [Ldap] Ldap Entry case-sensitive attribute key option …
fabpot Nov 27, 2020
3ac26fc
Remove extra docblock
fabpot Nov 27, 2020
4c74dea
Cache discovered namespaces in DomCrawler
simonberger Nov 16, 2020
a8e85ec
Make some CS changes
fabpot Nov 27, 2020
bd7a3e1
feature #39097 [DomCrawler] Cache discovered namespaces (simonberger,…
fabpot Nov 27, 2020
a2691d3
Merge branch '5.2' into 5.x
fabpot Nov 27, 2020
f0aa4e7
Merge branch '5.2' into 5.x
fabpot Nov 27, 2020
4981330
Merge branch '5.2' into 5.x
derrabus Nov 28, 2020
cf31b29
Merge branch '5.2' into 5.x
nicolas-grekas Nov 28, 2020
c31fc9d
Merge branch '5.2' into 5.x
nicolas-grekas Nov 28, 2020
55a67ff
Merge branch '5.2' into 5.x
derrabus Nov 28, 2020
f0dfb9e
Merge branch '5.2' into 5.x
derrabus Nov 29, 2020
4f59d2f
Merge branch '5.2' into 5.x
derrabus Nov 30, 2020
ff97b5f
Merge branch '5.2' into 5.x
derrabus Nov 30, 2020
6687e23
Add ContextBlock for slack notifier
norkunas Dec 1, 2020
e97f9e7
Merge branch '5.2' into 5.x
derrabus Dec 2, 2020
31ee43a
Merge branch '5.2' into 5.x
derrabus Dec 3, 2020
a7936d2
[Notifier] Check for maximum number of buttons in slack action block
malteschlueter Dec 3, 2020
53e1bc0
feature #39300 [Notifier] Check for maximum number of buttons in slac…
fabpot Dec 5, 2020
bb0362d
feature #39258 [Notifier] Add ContextBlock for slack notifier (norkunas)
fabpot Dec 5, 2020
4dd16d1
Fix CS
fabpot Dec 5, 2020
db4883d
Merge branch '5.2' into 5.x
fabpot Dec 5, 2020
b07608c
Move @experimental annotations to 5.3
fabpot Dec 5, 2020
21d4c09
minor #39320 Move @experimental annotations to 5.3 (fabpot)
fabpot Dec 5, 2020
1bf4341
Merge branch '5.2' into 5.x
derrabus Dec 5, 2020
de0dbd8
[DependencyInjection] Add missing parameter type declarations to load…
derrabus Dec 2, 2020
ce77be2
[Form] Changed DataMapperInterface $forms parameter type to \Traversable
vudaltsov Dec 5, 2020
37d823d
feature #39317 [Form] Changed DataMapperInterface $forms parameter ty…
derrabus Dec 5, 2020
ab31ee9
Search for pattern on debug:event-dispatcher
Nyholm Dec 5, 2020
caeac51
feature #39323 Search for pattern on debug:event-dispatcher (Nyholm)
fabpot Dec 5, 2020
751352c
minor #39292 [DependencyInjection] Add missing parameter type declara…
fabpot Dec 5, 2020
7dcaf98
Merge branch '5.2' into 5.x
fabpot Dec 5, 2020
a4b2606
Extracting ProgressBar's format's magic strings into const
CesarScur Nov 9, 2020
45519f2
[FrameworkBundle] Added support for configuring PHP error level to lo…
lyrixx Nov 6, 2020
df65ffe
feature #39042 [Console] Extracting ProgressBar's format's magic stri…
fabpot Dec 5, 2020
e6eef9b
bug #39018 [FrameworkBundle] Fixed validation of php_errors.log (lyrixx)
fabpot Dec 5, 2020
ffab85c
Merge branch '5.2' into 5.x
derrabus Dec 5, 2020
62398b5
[FrameworkBundle] Added option to specify the event dispatcher in deb…
TimoBakx Dec 1, 2020
86842ac
feature #39276 [FrameworkBundle] Added option to specify the event di…
derrabus Dec 5, 2020
8143f8a
Fix CS.
derrabus Dec 5, 2020
d907d3b
Fix broken link to documentation in Lock and Semaphore components
ronnylt Dec 6, 2020
9d40bd8
minor #39348 Fix broken link to documentation in Lock and Semaphore c…
Nyholm Dec 6, 2020
ffdfb4f
Assert voter returns valid decision
jderusse Dec 5, 2020
e9ab48f
Merge branch '5.2' into 5.x
derrabus Dec 7, 2020
41c5901
[FrameworkBundle] Add validator.expression_language service
fbourigault Dec 5, 2020
e9108e9
feature #39327 [FrameworkBundle] Add validator.expression_language se…
fabpot Dec 8, 2020
8fa2954
feature #39340 [Security] Assert voter returns valid decision (jderusse)
fabpot Dec 8, 2020
4da4f50
Merge branch '5.2' into 5.x
fabpot Dec 8, 2020
814ffab
[Cache] Support Redis Sentinel mode when using phpredis/phpredis exte…
renan Dec 7, 2020
979a539
feature #39363 [Cache] Support Redis Sentinel mode when using phpredi…
nicolas-grekas Dec 8, 2020
a885ba8
[Messenger] Use "warning" intead of "error" log level for Recoverable…
lyrixx Dec 8, 2020
620ee34
[Cache] hotfix
nicolas-grekas Dec 8, 2020
1ee7e4c
[HttpKernel] Marked the class `Symfony\Component\HttpKernel\EventList…
lyrixx Nov 30, 2020
d07b951
minor #39016 [HttpKernel] Marked the class DebugHandlersListener as i…
nicolas-grekas Dec 8, 2020
93c2f5e
[BrowserKit] Allowing body content from GET with a content-type
thiagomp Oct 18, 2020
219d511
feature #38622 [BrowserKit] Allowing body content from GET with a con…
nicolas-grekas Dec 8, 2020
7f9237e
[ErrorHandler] fix html W3C compliance
awoimbee Oct 8, 2020
0dce5cf
minor #38490 [ErrorHandler] fix html W3C compliance (awoimbee)
nicolas-grekas Dec 8, 2020
be5f6e5
Merge branch '5.2' into 5.x
nicolas-grekas Dec 8, 2020
e6f1136
Merge branch '5.2' into 5.x
nicolas-grekas Dec 8, 2020
fda67f5
Merge branch '5.2' into 5.x
nicolas-grekas Dec 8, 2020
266a6bb
Merge branch '5.2' into 5.x
nicolas-grekas Dec 9, 2020
8b8bffb
feature #39378 [Messenger] Use "warning" instead of "error" log level…
fabpot Dec 10, 2020
122eaba
[TwigBridge] export concatenated translations
Dec 6, 2020
b82bc85
feature #39352 [TwigBridge] export concatenated translations (Stephen)
fabpot Dec 10, 2020
1ce5b03
[Form] Add "choice_translation_parameters" option
VincentLanglet May 18, 2020
9b64be8
feature #38469 [Form] Add "choice_translation_parameters" option (Vin…
fabpot Dec 10, 2020
19b20ab
Merge branch '5.2' into 5.x
derrabus Dec 10, 2020
14e36a2
[Cache] Make use of `read_timeout` in `\RedisSentinel` and `\Redis`
ferrastas Dec 10, 2020
7c98ee1
bug #39431 [Cache] Make use of `read_timeout` in `\RedisSentinel` and…
nicolas-grekas Dec 10, 2020
276bbb5
[Cache] Bugfix provide the correct host and port when throwing the ex…
renan Dec 10, 2020
f66b853
bug #39434 [Cache] Bugfix provide the correct host and port when thro…
nicolas-grekas Dec 10, 2020
e4febad
Merge branch '5.2' into 5.x
nicolas-grekas Dec 10, 2020
d985ca9
[Messenger] Added more descriptive exception message when handling of…
loevgaard Dec 10, 2020
fccb4c9
minor #39423 [Messenger] Added more descriptive exception message whe…
nicolas-grekas Dec 10, 2020
61d9514
Merge branch '5.2' into 5.x
jderusse Dec 10, 2020
fb22eec
Fix CS in changelogs
jderusse Dec 10, 2020
67d2a20
minor #39441 Fix CS in changelogs (jderusse)
derrabus Dec 10, 2020
c6de408
Merge branch '5.2' into 5.x
nicolas-grekas Dec 10, 2020
b47b239
Merge branch '5.2' into 5.x
nicolas-grekas Dec 11, 2020
3c5e168
Fix #39468 with date immutable
FlorianM11 Dec 11, 2020
798a628
Added more tests
guillaume-sainthillier Dec 14, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
24 changes: 24 additions & 0 deletions UPGRADE-5.3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
UPGRADE FROM 5.2 to 5.3
=======================

Form
----

* Changed `$forms` parameter type of the `DataMapperInterface::mapDataToForms()` method from `iterable` to `\Traversable`.
* Changed `$forms` parameter type of the `DataMapperInterface::mapFormsToData()` method from `iterable` to `\Traversable`.
* Deprecated passing an array as the second argument of the `DataMapper::mapDataToForms()` method, pass `\Traversable` instead.
* Deprecated passing an array as the first argument of the `DataMapper::mapFormsToData()` method, pass `\Traversable` instead.
* Deprecated passing an array as the second argument of the `CheckboxListMapper::mapDataToForms()` method, pass `\Traversable` instead.
* Deprecated passing an array as the first argument of the `CheckboxListMapper::mapFormsToData()` method, pass `\Traversable` instead.
* Deprecated passing an array as the second argument of the `RadioListMapper::mapDataToForms()` method, pass `\Traversable` instead.
* Deprecated passing an array as the first argument of the `RadioListMapper::mapFormsToData()` method, pass `\Traversable` instead.

HttpKernel
----------

* Marked the class `Symfony\Component\HttpKernel\EventListener\DebugHandlersListener` as internal

Security
--------

* Deprecated voters that do not return a valid decision when calling the `vote` method.
7 changes: 7 additions & 0 deletions UPGRADE-6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ Form
* The `Symfony\Component\Form\Extension\Validator\Util\ServerParams` class has been removed, use its parent `Symfony\Component\Form\Util\ServerParams` instead.
* The `NumberToLocalizedStringTransformer::ROUND_*` constants have been removed, use `\NumberFormatter::ROUND_*` instead.
* Removed `PropertyPathMapper` in favor of `DataMapper` and `PropertyPathAccessor`.
* Changed `$forms` parameter type of the `DataMapper::mapDataToForms()` method from `iterable` to `\Traversable`.
* Changed `$forms` parameter type of the `DataMapper::mapFormsToData()` method from `iterable` to `\Traversable`.
* Changed `$checkboxes` parameter type of the `CheckboxListMapper::mapDataToForms()` method from `iterable` to `\Traversable`.
* Changed `$checkboxes` parameter type of the `CheckboxListMapper::mapFormsToData()` method from `iterable` to `\Traversable`.
* Changed `$radios` parameter type of the `RadioListMapper::mapDataToForms()` method from `iterable` to `\Traversable`.
* Changed `$radios` parameter type of the `RadioListMapper::mapFormsToData()` method from `iterable` to `\Traversable`.

FrameworkBundle
---------------
Expand Down Expand Up @@ -153,6 +159,7 @@ Security
in `PreAuthenticatedToken`, `RememberMeToken`, `SwitchUserToken`, `UsernamePasswordToken`,
`DefaultAuthenticationSuccessHandler`.
* Removed the `AbstractRememberMeServices::$providerKey` property in favor of `AbstractRememberMeServices::$firewallName`
* `AccessDecisionManager` now throw an exception when a voter does not return a valid decision.

TwigBundle
----------
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
"twig/markdown-extra": "^2.12"
},
"conflict": {
"async-aws/core": "<1.5",
"doctrine/dbal": "<2.10",
"masterminds/html5": "<2.6",
"phpdocumentor/reflection-docblock": "<3.2.2",
Expand Down Expand Up @@ -175,6 +176,6 @@
],
"minimum-stability": "dev",
"extra": {
"branch-version": "5.2"
"branch-version": "5.x"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function guessType(string $class, string $property)
case Types::DATETIMETZ_MUTABLE:
case 'vardatetime':
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateTimeType', [], Guess::HIGH_CONFIDENCE);
case Types::DATE_IMMUTABLE:
case Types::DATETIME_IMMUTABLE:
case Types::DATETIMETZ_IMMUTABLE:
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateTimeType', ['input' => 'datetime_immutable'], Guess::HIGH_CONFIDENCE);
case Types::DATEINTERVAL:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,40 @@

namespace Symfony\Bridge\Doctrine\Tests\Form;

use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\ObjectManager;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser;
use Symfony\Component\Form\Guess\Guess;
use Symfony\Component\Form\Guess\TypeGuess;
use Symfony\Component\Form\Guess\ValueGuess;

class DoctrineOrmTypeGuesserTest extends TestCase
{
/**
* @dataProvider requiredType
*/
public function testTypeGuesser($classMetadata, $expected)
{
$this->assertEquals($expected, $this->getGuesser($classMetadata)->guessType('TestEntity', 'field'));
}

public function requiredType()
{
$return = [];

// DateTime field
$classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')->disableOriginalConstructor()->getMock();
$classMetadata->fieldMappings['field'] = true;
$classMetadata->expects($this->once())->method('getTypeOfField')->with('field')->willReturn(Types::DATE_IMMUTABLE);

$return[] = [$classMetadata, new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', ['input' => 'datetime_immutable'], Guess::HIGH_CONFIDENCE)];

return $return;
}

/**
* @dataProvider requiredProvider
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bridge/Twig/Extension/CodeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public function fileExcerpt(string $file, int $line, int $srcContext = 3): ?stri
}

for ($i = max($line - $srcContext, 1), $max = min($line + $srcContext, \count($content)); $i <= $max; ++$i) {
$lines[] = '<li'.($i == $line ? ' class="selected"' : '').'><a class="anchor" name="line'.$i.'"></a><code>'.self::fixCodeMarkup($content[$i - 1]).'</code></li>';
$lines[] = '<li'.($i == $line ? ' class="selected"' : '').'><a class="anchor" id="line'.$i.'"></a><code>'.self::fixCodeMarkup($content[$i - 1]).'</code></li>';
}

return '<ol start="'.max($line - $srcContext, 1).'">'.implode("\n", $lines).'</ol>';
Expand Down
35 changes: 35 additions & 0 deletions src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Bridge\Twig\Node\TransNode;
use Twig\Environment;
use Twig\Node\Expression\Binary\ConcatBinary;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\FunctionExpression;
Expand Down Expand Up @@ -87,6 +88,16 @@ protected function doEnterNode(Node $node, Environment $env): Node
$node->getNode('body')->getAttribute('data'),
$node->hasNode('domain') ? $this->getReadDomainFromNode($node->getNode('domain')) : null,
];
} elseif (
$node instanceof FilterExpression &&
'trans' === $node->getNode('filter')->getAttribute('value') &&
$node->getNode('node') instanceof ConcatBinary &&
$message = $this->getConcatValueFromNode($node->getNode('node'), null)
) {
$this->messages[] = [
$message,
$this->getReadDomainFromArguments($node->getNode('arguments'), 1),
];
}

return $node;
Expand Down Expand Up @@ -151,4 +162,28 @@ private function getReadDomainFromNode(Node $node): ?string

return self::UNDEFINED_DOMAIN;
}

private function getConcatValueFromNode(Node $node, ?string $value): ?string
{
if ($node instanceof ConcatBinary) {
foreach ($node as $nextNode) {
if ($nextNode instanceof ConcatBinary) {
$nextValue = $this->getConcatValueFromNode($nextNode, $value);
if (null === $nextValue) {
return null;
}
$value .= $nextValue;
} elseif ($nextNode instanceof ConstantExpression) {
$value .= $nextNode->getAttribute('value');
} else {
// this is a node we cannot process (variable, or translation in translation)
return null;
}
}
} elseif ($node instanceof ConstantExpression) {
$value .= $node->getAttribute('value');
}

return $value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
{{- block('choice_widget_options') -}}
</optgroup>
{%- else -%}
<option value="{{ choice.value }}"{% if choice.attr %}{% with { attr: choice.attr } %}{{ block('attributes') }}{% endwith %}{% endif %}{% if not render_preferred_choices|default(false) and choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice_translation_domain is same as(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}</option>
<option value="{{ choice.value }}"{% if choice.attr %}{% with { attr: choice.attr } %}{{ block('attributes') }}{% endwith %}{% endif %}{% if not render_preferred_choices|default(false) and choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice_translation_domain is same as(false) ? choice.label : choice.label|trans(choice.labelTranslationParameters, choice_translation_domain) }}</option>
{%- endif -%}
{% endfor %}
{%- endblock choice_widget_options -%}
Expand Down
13 changes: 13 additions & 0 deletions src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public function testExtract($template, $messages)
$m->setAccessible(true);
$m->invoke($extractor, $template, $catalogue);

if (0 === \count($messages)) {
$this->assertSame($catalogue->all(), $messages);
}

foreach ($messages as $key => $domain) {
$this->assertTrue($catalogue->has($key, $domain));
$this->assertEquals('prefix'.$key, $catalogue->get($key, $domain));
Expand Down Expand Up @@ -70,6 +74,15 @@ public function getExtractData()

// make sure this works with twig's named arguments
['{{ "new key" | trans(domain="domain") }}', ['new key' => 'domain']],

// concat translations
['{{ ("new" ~ " key") | trans() }}', ['new key' => 'messages']],
['{{ ("another " ~ "new " ~ "key") | trans() }}', ['another new key' => 'messages']],
['{{ ("new" ~ " key") | trans(domain="domain") }}', ['new key' => 'domain']],
['{{ ("another " ~ "new " ~ "key") | trans(domain="domain") }}', ['another new key' => 'domain']],
// if it has a variable or other expression, we can not extract it
['{% set foo = "new" %} {{ ("new " ~ foo ~ "key") | trans() }}', []],
['{{ ("foo " ~ "new"|trans ~ "key") | trans() }}', ['new' => 'messages']],
];
}

Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Bridge/Twig/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"symfony/asset": "^4.4|^5.0",
"symfony/dependency-injection": "^4.4|^5.0",
"symfony/finder": "^4.4|^5.0",
"symfony/form": "^5.1.9",
"symfony/form": "^5.3",
"symfony/http-foundation": "^4.4|^5.0",
"symfony/http-kernel": "^4.4|^5.0",
"symfony/mime": "^5.2",
Expand All @@ -52,7 +52,7 @@
},
"conflict": {
"symfony/console": "<4.4",
"symfony/form": "<5.1",
"symfony/form": "<5.3",
"symfony/http-foundation": "<4.4",
"symfony/http-kernel": "<4.4",
"symfony/translation": "<5.2",
Expand Down
7 changes: 7 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
CHANGELOG
=========

5.3.0
-----

* Added support for configuring PHP error level to log levels
* Added the `dispatcher` option to `debug:event-dispatcher`
* Added the `event_dispatcher.dispatcher` tag

5.2.0
-----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Bundle\FrameworkBundle\Command;

use Psr\Container\ContainerInterface;
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand All @@ -29,14 +30,16 @@
*/
class EventDispatcherDebugCommand extends Command
{
private const DEFAULT_DISPATCHER = 'event_dispatcher';

protected static $defaultName = 'debug:event-dispatcher';
private $dispatcher;
private $dispatchers;

public function __construct(EventDispatcherInterface $dispatcher)
public function __construct(ContainerInterface $dispatchers)
{
parent::__construct();

$this->dispatcher = $dispatcher;
$this->dispatchers = $dispatchers;
}

/**
Expand All @@ -46,7 +49,8 @@ protected function configure()
{
$this
->setDefinition([
new InputArgument('event', InputArgument::OPTIONAL, 'An event name'),
new InputArgument('event', InputArgument::OPTIONAL, 'An event name or a part of the event name'),
new InputOption('dispatcher', null, InputOption::VALUE_REQUIRED, 'To view events of a specific event dispatcher', self::DEFAULT_DISPATCHER),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
])
Expand Down Expand Up @@ -74,22 +78,57 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$io = new SymfonyStyle($input, $output);

$options = [];
if ($event = $input->getArgument('event')) {
if (!$this->dispatcher->hasListeners($event)) {
$io->getErrorStyle()->warning(sprintf('The event "%s" does not have any registered listeners.', $event));
$dispatcherServiceName = $input->getOption('dispatcher');
if (!$this->dispatchers->has($dispatcherServiceName)) {
$io->getErrorStyle()->error(sprintf('Event dispatcher "%s" is not available.', $dispatcherServiceName));

return 0;
}
return 1;
}

$options = ['event' => $event];
$dispatcher = $this->dispatchers->get($dispatcherServiceName);

if ($event = $input->getArgument('event')) {
if ($dispatcher->hasListeners($event)) {
$options = ['event' => $event];
} else {
// if there is no direct match, try find partial matches
$events = $this->searchForEvent($dispatcher, $event);
if (0 === \count($events)) {
$io->getErrorStyle()->warning(sprintf('The event "%s" does not have any registered listeners.', $event));

return 0;
} elseif (1 === \count($events)) {
$options = ['event' => $events[array_key_first($events)]];
} else {
$options = ['events' => $events];
}
}
}

$helper = new DescriptorHelper();

if (self::DEFAULT_DISPATCHER !== $dispatcherServiceName) {
$options['dispatcher_service_name'] = $dispatcherServiceName;
}

$options['format'] = $input->getOption('format');
$options['raw_text'] = $input->getOption('raw');
$options['output'] = $io;
$helper->describe($io, $this->dispatcher, $options);
$helper->describe($io, $dispatcher, $options);

return 0;
}

private function searchForEvent(EventDispatcherInterface $dispatcher, $needle): array
{
$output = [];
$allEvents = array_keys($dispatcher->getListeners());
foreach ($allEvents as $event) {
if (str_contains($event, $needle)) {
$output[] = $event;
}
}

return $output;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ protected function describeContainerAlias(Alias $alias, array $options = [], Con

protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = [])
{
$this->writeData($this->getEventDispatcherListenersData($eventDispatcher, \array_key_exists('event', $options) ? $options['event'] : null), $options);
$this->writeData($this->getEventDispatcherListenersData($eventDispatcher, $options), $options);
}

protected function describeCallable($callable, array $options = [])
Expand Down Expand Up @@ -274,18 +274,19 @@ private function getContainerAliasData(Alias $alias): array
];
}

private function getEventDispatcherListenersData(EventDispatcherInterface $eventDispatcher, string $event = null): array
private function getEventDispatcherListenersData(EventDispatcherInterface $eventDispatcher, array $options): array
{
$data = [];
$event = \array_key_exists('event', $options) ? $options['event'] : null;

$registeredListeners = $eventDispatcher->getListeners($event);
if (null !== $event) {
foreach ($registeredListeners as $listener) {
foreach ($eventDispatcher->getListeners($event) as $listener) {
$l = $this->getCallableData($listener);
$l['priority'] = $eventDispatcher->getListenerPriority($event, $listener);
$data[] = $l;
}
} else {
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(function ($event) use ($eventDispatcher) { return $eventDispatcher->getListeners($event); }, $options['events'])) : $eventDispatcher->getListeners();
ksort($registeredListeners);

foreach ($registeredListeners as $eventListened => $eventListeners) {
Expand Down
Loading