Skip to content

Commit 4e0ff10

Browse files
committed
Merge branch '7.0' into 7.1
* 7.0: [Messenger] Fix using negative delay [Validator] Add missing italian translation [Validator] Fix using known option names as field names [SecurityBundle] Prevent to login/logout without a request context Suppress warnings from is_executable Fix expected return type
2 parents 029ca7e + b3ab27f commit 4e0ff10

File tree

7 files changed

+128
-8
lines changed

7 files changed

+128
-8
lines changed

src/Symfony/Bundle/SecurityBundle/Security.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ public function getFirewallConfig(Request $request): ?FirewallConfig
8484
public function login(UserInterface $user, string $authenticatorName = null, string $firewallName = null, array $badges = []): ?Response
8585
{
8686
$request = $this->container->get('request_stack')->getCurrentRequest();
87+
if (null === $request) {
88+
throw new LogicException('Unable to login without a request context.');
89+
}
90+
8791
$firewallName ??= $this->getFirewallConfig($request)?->getName();
8892

8993
if (!$firewallName) {
@@ -108,15 +112,18 @@ public function login(UserInterface $user, string $authenticatorName = null, str
108112
*/
109113
public function logout(bool $validateCsrfToken = true): ?Response
110114
{
115+
$request = $this->container->get('request_stack')->getMainRequest();
116+
if (null === $request) {
117+
throw new LogicException('Unable to logout without a request context.');
118+
}
119+
111120
/** @var TokenStorageInterface $tokenStorage */
112121
$tokenStorage = $this->container->get('security.token_storage');
113122

114123
if (!($token = $tokenStorage->getToken()) || !$token->getUser()) {
115124
throw new LogicException('Unable to logout as there is no logged-in user.');
116125
}
117126

118-
$request = $this->container->get('request_stack')->getMainRequest();
119-
120127
if (!$firewallConfig = $this->container->get('security.firewall.map')->getFirewallConfig($request)) {
121128
throw new LogicException('Unable to logout as the request is not behind a firewall.');
122129
}

src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,28 @@ public function testLoginWithoutAuthenticatorThrows()
252252
$security->login($user);
253253
}
254254

255+
public function testLoginWithoutRequestContext()
256+
{
257+
$requestStack = new RequestStack();
258+
$user = $this->createMock(UserInterface::class);
259+
260+
$container = $this->createMock(ContainerInterface::class);
261+
$container
262+
->expects($this->atLeastOnce())
263+
->method('get')
264+
->willReturnMap([
265+
['request_stack', $requestStack],
266+
])
267+
;
268+
269+
$security = new Security($container, ['main' => null]);
270+
271+
$this->expectException(\LogicException::class);
272+
$this->expectExceptionMessage('Unable to login without a request context.');
273+
274+
$security->login($user);
275+
}
276+
255277
public function testLogout()
256278
{
257279
$request = new Request();
@@ -458,6 +480,27 @@ public function testLogoutWithValidCsrf()
458480
$this->assertEquals('a custom response', $response->getContent());
459481
}
460482

483+
public function testLogoutWithoutRequestContext()
484+
{
485+
$requestStack = new RequestStack();
486+
487+
$container = $this->createMock(ContainerInterface::class);
488+
$container
489+
->expects($this->atLeastOnce())
490+
->method('get')
491+
->willReturnMap([
492+
['request_stack', $requestStack],
493+
])
494+
;
495+
496+
$security = new Security($container, ['main' => null]);
497+
498+
$this->expectException(\LogicException::class);
499+
$this->expectExceptionMessage('Unable to logout without a request context.');
500+
501+
$security->logout();
502+
}
503+
461504
private function createContainer(string $serviceId, object $serviceObject): ContainerInterface
462505
{
463506
return new ServiceLocator([$serviceId => fn () => $serviceObject]);

src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,29 @@ public function testSendWithDelay()
6464
// DBAL 2 compatibility
6565
$result = method_exists($qb, 'executeQuery') ? $qb->executeQuery() : $qb->execute();
6666

67-
$available_at = new \DateTimeImmutable($result->fetchOne());
67+
$availableAt = new \DateTimeImmutable($result->fetchOne());
6868

6969
$now = new \DateTimeImmutable('now + 60 seconds');
70-
$this->assertGreaterThan($now, $available_at);
70+
$this->assertGreaterThan($now, $availableAt);
71+
}
72+
73+
public function testSendWithNegativeDelay()
74+
{
75+
$this->connection->send('{"message": "Hi, I am not actually delayed"}', ['type' => DummyMessage::class], -600000);
76+
77+
$qb = $this->driverConnection->createQueryBuilder()
78+
->select('m.available_at')
79+
->from('messenger_messages', 'm')
80+
->where('m.body = :body')
81+
->setParameter('body', '{"message": "Hi, I am not actually delayed"}');
82+
83+
// DBAL 2 compatibility
84+
$result = method_exists($qb, 'executeQuery') ? $qb->executeQuery() : $qb->execute();
85+
86+
$availableAt = new \DateTimeImmutable($result->fetchOne());
87+
88+
$now = new \DateTimeImmutable('now - 60 seconds');
89+
$this->assertLessThan($now, $availableAt);
7190
}
7291

7392
public function testItRetrieveTheFirstAvailableMessage()

src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public static function buildConfiguration(#[\SensitiveParameter] string $dsn, ar
122122
public function send(string $body, array $headers, int $delay = 0): string
123123
{
124124
$now = new \DateTimeImmutable('UTC');
125-
$availableAt = $now->modify(sprintf('+%d seconds', $delay / 1000));
125+
$availableAt = $now->modify(sprintf('%+d seconds', $delay / 1000));
126126

127127
$queryBuilder = $this->driverConnection->createQueryBuilder()
128128
->insert($this->configuration['table_name'])

src/Symfony/Component/Process/ExecutableFinder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function find(string $name, string $default = null, array $extraDirs = []
6969
}
7070

7171
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v';
72-
if (\function_exists('exec') && ($executablePath = strtok(@exec($command.' '.escapeshellarg($name)), \PHP_EOL)) && is_executable($executablePath)) {
72+
if (\function_exists('exec') && ($executablePath = strtok(@exec($command.' '.escapeshellarg($name)), \PHP_EOL)) && @is_executable($executablePath)) {
7373
return $executablePath;
7474
}
7575

src/Symfony/Component/Validator/Constraints/Collection.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Validator\Constraints;
1313

14+
use Symfony\Component\Validator\Constraint;
15+
1416
/**
1517
* @author Bernhard Schussek <[email protected]>
1618
*/
@@ -33,9 +35,10 @@ class Collection extends Composite
3335

3436
public function __construct(array $fields = null, array $groups = null, mixed $payload = null, bool $allowExtraFields = null, bool $allowMissingFields = null, string $extraFieldsMessage = null, string $missingFieldsMessage = null)
3537
{
36-
// no known options set? $fields is the fields array
3738
if (\is_array($fields)
38-
&& !array_intersect(array_keys($fields), ['groups', 'fields', 'allowExtraFields', 'allowMissingFields', 'extraFieldsMessage', 'missingFieldsMessage'])) {
39+
&& (($firstField = reset($fields)) instanceof Constraint
40+
|| ($firstField[0] ?? null) instanceof Constraint
41+
)) {
3942
$fields = ['fields' => $fields];
4043
}
4144

src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,21 @@
1818
use Symfony\Component\Validator\Constraints\Required;
1919
use Symfony\Component\Validator\Constraints\Valid;
2020
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
21+
use Symfony\Component\Validator\Exception\InvalidOptionsException;
2122

2223
/**
2324
* @author Bernhard Schussek <[email protected]>
2425
*/
2526
class CollectionTest extends TestCase
2627
{
28+
public function testRejectNonConstraints()
29+
{
30+
$this->expectException(InvalidOptionsException::class);
31+
new Collection([
32+
'foo' => 'bar',
33+
]);
34+
}
35+
2736
public function testRejectValidConstraint()
2837
{
2938
$this->expectException(ConstraintDefinitionException::class);
@@ -97,4 +106,43 @@ public function testConstraintHasDefaultGroupWithOptionalValues()
97106
$this->assertEquals(['Default'], $constraint->fields['foo']->groups);
98107
$this->assertEquals(['Default'], $constraint->fields['bar']->groups);
99108
}
109+
110+
public function testOnlySomeKeysAreKnowOptions()
111+
{
112+
$constraint = new Collection([
113+
'fields' => [new Required()],
114+
'properties' => [new Required()],
115+
'catalog' => [new Optional()],
116+
]);
117+
118+
$this->assertArrayHasKey('fields', $constraint->fields);
119+
$this->assertInstanceOf(Required::class, $constraint->fields['fields']);
120+
$this->assertArrayHasKey('properties', $constraint->fields);
121+
$this->assertInstanceOf(Required::class, $constraint->fields['properties']);
122+
$this->assertArrayHasKey('catalog', $constraint->fields);
123+
$this->assertInstanceOf(Optional::class, $constraint->fields['catalog']);
124+
}
125+
126+
public function testAllKeysAreKnowOptions()
127+
{
128+
$constraint = new Collection([
129+
'fields' => [
130+
'fields' => [new Required()],
131+
'properties' => [new Required()],
132+
'catalog' => [new Optional()],
133+
],
134+
'allowExtraFields' => true,
135+
'extraFieldsMessage' => 'foo bar baz',
136+
]);
137+
138+
$this->assertArrayHasKey('fields', $constraint->fields);
139+
$this->assertInstanceOf(Required::class, $constraint->fields['fields']);
140+
$this->assertArrayHasKey('properties', $constraint->fields);
141+
$this->assertInstanceOf(Required::class, $constraint->fields['properties']);
142+
$this->assertArrayHasKey('catalog', $constraint->fields);
143+
$this->assertInstanceOf(Optional::class, $constraint->fields['catalog']);
144+
145+
$this->assertTrue($constraint->allowExtraFields);
146+
$this->assertSame('foo bar baz', $constraint->extraFieldsMessage);
147+
}
100148
}

0 commit comments

Comments
 (0)