Skip to content

Commit

Permalink
Merge branch '6.2' into 6.3
Browse files Browse the repository at this point in the history
* 6.2:
  cs fix
  [Messenger] Fix passing options set via tags to handler descriptors
  random_bytes length should be an int greater than 0
  enforce UTC timezone in test
  [DependencyInjection] Fix autocasting null env values to empty string
  Fix executable bit
  Fix executable bit
  Readme: Replace Stack Overflow with GitHub Discussions
  [DoctrineBridge] Remove outdated comment
  [DependencyInjection] Fix annotation
  [SecurityBundle] Do not translate `Bearer` header’s `error_description`
  [String] Fix Inflector for 'status'
  [DependencyInjection] Fix resource tracking for lazy services
  [EventDispatcher] [EventDispatcher] Throw exception when listener method cannot be resolved
  • Loading branch information
nicolas-grekas committed Jul 5, 2023
2 parents 9b2ac59 + 6fc09d9 commit 16121cf
Show file tree
Hide file tree
Showing 27 changed files with 161 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Community
---------

* [Join the Symfony Community][11] and meet other members at the [Symfony events][12].
* [Get Symfony support][13] on Stack Overflow, Slack, IRC, etc.
* [Get Symfony support][13] on GitHub Discussions, Slack, etc.
* Follow us on [GitHub][14], [Twitter][15] and [Facebook][16].
* Read our [Code of Conduct][24] and meet the [CARE Team][25].

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ protected function loadChoices(): iterable
: $this->manager->getRepository($this->class)->findAll();
}

/**
* @internal to be remove in Symfony 6
*/
protected function doLoadValuesForChoices(array $choices): array
{
// Optimize performance for single-field identifiers. We already
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
null,
null,
])
->call('setTranslator', [service('translator')->ignoreOnInvalid()])

->set('security.authenticator.access_token.chain_extractor', ChainAccessTokenExtractor::class)
->abstract()
Expand Down
10 changes: 9 additions & 1 deletion src/Symfony/Component/DependencyInjection/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,15 @@ protected function getEnv(string $name): mixed
$prefix = 'string';
$localName = $name;
}
$processor = $processors->has($prefix) ? $processors->get($prefix) : new EnvVarProcessor($this);

if ($processors->has($prefix)) {
$processor = $processors->get($prefix);
} else {
$processor = new EnvVarProcessor($this);
if (false === $i) {
$prefix = '';
}
}

$this->resolving[$envName] = true;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
trait ContainerAwareTrait
{
/**
* @var ContainerInterface
* @var ContainerInterface|null
*/
protected $container;

Expand Down
16 changes: 14 additions & 2 deletions src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Dumper;

use Composer\Autoload\ClassLoader;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
Expand Down Expand Up @@ -581,8 +582,19 @@ private function generateProxyClasses(): array
continue;
}
$alreadyGenerated[$asGhostObject][$class] = true;
// register class' reflector for resource tracking
$this->container->getReflectionClass($class);

$r = $this->container->getReflectionClass($class);
do {
$file = $r->getFileName();
if (str_ends_with($file, ') : eval()\'d code')) {
$file = substr($file, 0, strrpos($file, '(', -17));
}
if (is_file($file)) {
$this->container->addResource(new FileResource($file));
}
$r = $r->getParentClass() ?: null;
} while ($r?->isUserDefined());

if ("\n" === $proxyCode = "\n".$proxyDumper->getProxyCode($definition, $id)) {
continue;
}
Expand Down
10 changes: 10 additions & 0 deletions src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ public function getEnv(string $prefix, string $name, \Closure $getEnv): mixed
}
}

$returnNull = false;
if ('' === $prefix) {
$returnNull = true;
$prefix = 'string';
}

if (false !== $i || 'string' !== $prefix) {
$env = $getEnv($name);
} elseif ('' === ($env = $_ENV[$name] ?? (str_starts_with($name, 'HTTP_') ? null : ($_SERVER[$name] ?? null)))
Expand Down Expand Up @@ -192,6 +198,10 @@ public function getEnv(string $prefix, string $name, \Closure $getEnv): mixed
}

if (null === $env) {
if ($returnNull) {
return null;
}

if (!isset($this->getProvidedTypes()[$prefix])) {
throw new RuntimeException(sprintf('Unsupported env var prefix "%s".', $prefix));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -910,12 +910,13 @@ public static function provideGetEnvUrlPath()

/**
* @testWith ["", "string"]
* [null, ""]
* [false, "bool"]
* [true, "not"]
* [0, "int"]
* [0.0, "float"]
*/
public function testGetEnvCastsNull($expected, string $prefix)
public function testGetEnvCastsNullBehavior($expected, string $prefix)
{
$processor = new EnvVarProcessor(new Container());

Expand All @@ -925,4 +926,17 @@ public function testGetEnvCastsNull($expected, string $prefix)
});
}));
}

public function testGetEnvWithEmptyStringPrefixCastsToString()
{
$processor = new EnvVarProcessor(new Container());
unset($_ENV['FOO']);
$_ENV['FOO'] = 4;

try {
$this->assertSame('4', $processor->getEnv('', 'FOO', function () { $this->fail('Should not be called'); }));
} finally {
unset($_ENV['FOO']);
}
}
}
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ public function process(ContainerBuilder $container)
], fn ($matches) => strtoupper($matches[0]), $event['event']);
$event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']);

if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method']) && $r->hasMethod('__invoke')) {
if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method'])) {
if (!$r->hasMethod('__invoke')) {
throw new InvalidArgumentException(sprintf('None of the "%s" or "__invoke" methods exist for the service "foo". Please define the "method" attribute on "kernel.event_listener" tags.', $event['method'], $id, $this->listenerTag));
}

$event['method'] = '__invoke';
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,20 @@ public function testEventSubscriberUnresolvableClassName()
public function testInvokableEventListener()
{
$container = new ContainerBuilder();
$container->register('foo', \stdClass::class)->addTag('kernel.event_listener', ['event' => 'foo.bar']);
$container->setParameter('event_dispatcher.event_aliases', [AliasedEvent::class => 'aliased_event']);

$container->register('foo', \get_class(new class() {
public function onFooBar()
{
}
}))->addTag('kernel.event_listener', ['event' => 'foo.bar']);
$container->register('bar', InvokableListenerService::class)->addTag('kernel.event_listener', ['event' => 'foo.bar']);
$container->register('baz', InvokableListenerService::class)->addTag('kernel.event_listener', ['event' => 'event']);
$container->register('zar', \stdClass::class)->addTag('kernel.event_listener', ['event' => 'foo.bar_zar']);
$container->register('zar', \get_class(new class() {
public function onFooBarZar()
{
}
}))->addTag('kernel.event_listener', ['event' => 'foo.bar_zar']);
$container->register('event_dispatcher', \stdClass::class);

$registerListenersPass = new RegisterListenersPass();
Expand Down Expand Up @@ -247,6 +257,20 @@ public function testInvokableEventListener()
$this->assertEquals($expectedCalls, $definition->getMethodCalls());
}

public function testItThrowsAnExceptionIfTagIsMissingMethodAndClassHasNoValidMethod()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('None of the "onFooBar" or "__invoke" methods exist for the service "foo". Please define the "method" attribute on "kernel.event_listener" tags.');

$container = new ContainerBuilder();

$container->register('foo', \stdClass::class)->addTag('kernel.event_listener', ['event' => 'foo.bar']);
$container->register('event_dispatcher', \stdClass::class);

$registerListenersPass = new RegisterListenersPass();
$registerListenersPass->process($container);
}

public function testTaggedInvokableEventListener()
{
$container = new ContainerBuilder();
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,9 @@ private function registerHandlers(ContainerBuilder $container, array $busIds): v
$options = ['method' => $options];
}

if (!isset($options['from_transport']) && isset($tag['from_transport'])) {
$options['from_transport'] = $tag['from_transport'];
}

$priority = $tag['priority'] ?? $options['priority'] ?? 0;
$options += array_filter($tag);
unset($options['handles']);
$priority = $options['priority'] ?? 0;
$method = $options['method'] ?? '__invoke';

if (isset($options['bus'])) {
Expand All @@ -115,7 +113,7 @@ private function registerHandlers(ContainerBuilder $container, array $busIds): v
// $messageLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method);
$messageLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : ($r->implementsInterface(MessageSubscriberInterface::class) ? sprintf('returned by method "%s::getHandledMessages()"', $r->getName()) : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method));

throw new RuntimeException(sprintf('Invalid configuration "%s" for message "%s": bus "%s" does not exist.', $messageLocation, $message, $options['bus']));
throw new RuntimeException(sprintf('Invalid configuration '.$messageLocation.' for message "%s": bus "%s" does not exist.', $message, $options['bus']));
}

$buses = [$options['bus']];
Expand All @@ -126,7 +124,7 @@ private function registerHandlers(ContainerBuilder $container, array $busIds): v
// $messageLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method);
$messageLocation = isset($tag['handles']) ? 'declared in your tag attribute "handles"' : ($r->implementsInterface(MessageSubscriberInterface::class) ? sprintf('returned by method "%s::getHandledMessages()"', $r->getName()) : sprintf('used as argument type in method "%s::%s()"', $r->getName(), $method));

throw new RuntimeException(sprintf('Invalid handler service "%s": class or interface "%s" "%s" not found.', $serviceId, $message, $messageLocation));
throw new RuntimeException(sprintf('Invalid handler service "%s": class or interface "%s" '.$messageLocation.' not found.', $serviceId, $message));
}

if (!$r->hasMethod($method)) {
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,15 @@ public function testProcessHandlersByBus()
$container,
$commandBusHandlersLocatorDefinition->getArgument(0),
MultipleBusesMessage::class,
[MultipleBusesMessageHandler::class]
[MultipleBusesMessageHandler::class],
[['bus' => $commandBusId]]
);
$this->assertHandlerDescriptor(
$container,
$commandBusHandlersLocatorDefinition->getArgument(0),
DummyCommand::class,
[DummyCommandHandler::class]
[DummyCommandHandler::class],
[['bus' => $commandBusId]]
);

$queryBusHandlersLocatorDefinition = $container->getDefinition($queryBusId.'.messenger.handlers_locator');
Expand All @@ -283,13 +285,15 @@ public function testProcessHandlersByBus()
$container,
$queryBusHandlersLocatorDefinition->getArgument(0),
DummyQuery::class,
[DummyQueryHandler::class]
[DummyQueryHandler::class],
[['bus' => $queryBusId]]
);
$this->assertHandlerDescriptor(
$container,
$queryBusHandlersLocatorDefinition->getArgument(0),
MultipleBusesMessage::class,
[MultipleBusesMessageHandler::class]
[MultipleBusesMessageHandler::class],
[['bus' => $queryBusId]]
);
}

Expand Down Expand Up @@ -559,7 +563,7 @@ public function testItRegistersHandlersOnDifferentBuses()
public function testItThrowsAnExceptionOnUnknownBus()
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Invalid configuration "returned by method "Symfony\Component\Messenger\Tests\DependencyInjection\HandlerOnUndefinedBus::getHandledMessages()"" for message "Symfony\Component\Messenger\Tests\Fixtures\DummyMessage": bus "some_undefined_bus" does not exist.');
$this->expectExceptionMessage('Invalid configuration returned by method "Symfony\Component\Messenger\Tests\DependencyInjection\HandlerOnUndefinedBus::getHandledMessages()" for message "Symfony\Component\Messenger\Tests\Fixtures\DummyMessage": bus "some_undefined_bus" does not exist.');
$container = $this->getContainerBuilder();
$container
->register(HandlerOnUndefinedBus::class, HandlerOnUndefinedBus::class)
Expand All @@ -572,7 +576,7 @@ public function testItThrowsAnExceptionOnUnknownBus()
public function testUndefinedMessageClassForHandler()
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandler": class or interface "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessage" "used as argument type in method "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandler::__invoke()"" not found.');
$this->expectExceptionMessage('Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandler": class or interface "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessage" used as argument type in method "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandler::__invoke()" not found.');
$container = $this->getContainerBuilder();
$container
->register(UndefinedMessageHandler::class, UndefinedMessageHandler::class)
Expand All @@ -588,7 +592,7 @@ public function testUndefinedMessageClassForHandler()
public function testUndefinedMessageClassForHandlerImplementingMessageHandlerInterface()
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandlerViaHandlerInterface": class or interface "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessage" "used as argument type in method "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandlerViaHandlerInterface::__invoke()"" not found.');
$this->expectExceptionMessage('Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandlerViaHandlerInterface": class or interface "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessage" used as argument type in method "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandlerViaHandlerInterface::__invoke()" not found.');
$container = $this->getContainerBuilder();
$container
->register(UndefinedMessageHandlerViaHandlerInterface::class, UndefinedMessageHandlerViaHandlerInterface::class)
Expand All @@ -604,7 +608,7 @@ public function testUndefinedMessageClassForHandlerImplementingMessageHandlerInt
public function testUndefinedMessageClassForHandlerImplementingMessageSubscriberInterface()
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandlerViaSubscriberInterface": class or interface "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessage" "returned by method "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandlerViaSubscriberInterface::getHandledMessages()"" not found.');
$this->expectExceptionMessage('Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandlerViaSubscriberInterface": class or interface "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessage" returned by method "Symfony\Component\Messenger\Tests\DependencyInjection\UndefinedMessageHandlerViaSubscriberInterface::getHandledMessages()" not found.');
$container = $this->getContainerBuilder();
$container
->register(UndefinedMessageHandlerViaSubscriberInterface::class, UndefinedMessageHandlerViaSubscriberInterface::class)
Expand Down Expand Up @@ -833,12 +837,12 @@ public function testItRegistersTheDebugCommand()

$this->assertEquals([
$commandBusId => [
DummyCommand::class => [[DummyCommandHandler::class, []]],
MultipleBusesMessage::class => [[MultipleBusesMessageHandler::class, []]],
DummyCommand::class => [[DummyCommandHandler::class, ['bus' => $commandBusId]]],
MultipleBusesMessage::class => [[MultipleBusesMessageHandler::class, ['bus' => $commandBusId]]],
],
$queryBusId => [
DummyQuery::class => [[DummyQueryHandler::class, []]],
MultipleBusesMessage::class => [[MultipleBusesMessageHandler::class, []]],
DummyQuery::class => [[DummyQueryHandler::class, ['bus' => $queryBusId]]],
MultipleBusesMessage::class => [[MultipleBusesMessageHandler::class, ['bus' => $queryBusId]]],
],
$emptyBus => [],
], $container->getDefinition('console.command.messenger_debug')->getArgument(0));
Expand Down
Empty file.
Empty file modified src/Symfony/Component/Process/Tests/ErrorProcessInitiator.php
100755 → 100644
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,28 @@ public function testGenerateToken()
$this->assertStringNotMatchesFormat('%S/%S', $token, 'is URI safe');
$this->assertStringNotMatchesFormat('%S=%S', $token, 'is URI safe');
}

/**
* @dataProvider validDataProvider
*/
public function testValidLength(int $entropy, int $length)
{
$generator = new UriSafeTokenGenerator($entropy);
$token = $generator->generateToken();
$this->assertSame($length, \strlen($token));
}

public static function validDataProvider(): \Iterator
{
yield [24, 4];
yield 'Float length' => [20, 3];
}

public function testInvalidLength()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Entropy should be greater than 7.');

new UriSafeTokenGenerator(7);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class UriSafeTokenGenerator implements TokenGeneratorInterface
*/
public function __construct(int $entropy = 256)
{
if ($entropy <= 7) {
throw new \InvalidArgumentException('Entropy should be greater than 7.');
}

$this->entropy = $entropy;
}

Expand All @@ -35,7 +39,7 @@ public function generateToken(): string
// Generate an URI safe base64 encoded string that does not contain "+",
// "/" or "=" which need to be URL encoded and make URLs unnecessarily
// longer.
$bytes = random_bytes($this->entropy / 8);
$bytes = random_bytes(intdiv($this->entropy, 8));

return rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
}
Expand Down
Loading

0 comments on commit 16121cf

Please sign in to comment.