Skip to content

Commit 0a9eb28

Browse files
committed
Merge branch '7.2' into 7.3
* 7.2: relax assertions on generated hashes [Messenger] ensure exception on rollback does not hide previous exception require the writer to implement getFormats() in the translation:extract don't require fake notifier transports to be installed as non-dev dependencies Remove 5.4 branch from PR template [Scheduler] Fix optional count variable in testGetNextRunDates fix translation lint compatibility with the PseudoLocalizationTranslator set the violation path only if the "errorPath" option is set
2 parents dd061aa + ebbdb22 commit 0a9eb28

File tree

17 files changed

+176
-56
lines changed

17 files changed

+176
-56
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
| Q | A
22
| ------------- | ---
3-
| Branch? | 7.3 for features / 5.4, 6.4, 7.1, and 7.2 for bug fixes <!-- see below -->
3+
| Branch? | 7.3 for features / 6.4, 7.1, and 7.2 for bug fixes <!-- see below -->
44
| Bug fix? | yes/no
55
| New feature? | yes/no <!-- please update src/**/CHANGELOG.md files -->
66
| Deprecations? | yes/no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->

src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,30 @@ class DoctrineTransactionMiddleware extends AbstractDoctrineMiddleware
2727
protected function handleForManager(EntityManagerInterface $entityManager, Envelope $envelope, StackInterface $stack): Envelope
2828
{
2929
$entityManager->getConnection()->beginTransaction();
30+
31+
$success = false;
3032
try {
3133
$envelope = $stack->next()->handle($envelope, $stack);
3234
$entityManager->flush();
3335
$entityManager->getConnection()->commit();
3436

37+
$success = true;
38+
3539
return $envelope;
3640
} catch (\Throwable $exception) {
37-
$entityManager->getConnection()->rollBack();
38-
3941
if ($exception instanceof HandlerFailedException) {
4042
// Remove all HandledStamp from the envelope so the retry will execute all handlers again.
4143
// When a handler fails, the queries of allegedly successful previous handlers just got rolled back.
4244
throw new HandlerFailedException($exception->getEnvelope()->withoutAll(HandledStamp::class), $exception->getWrappedExceptions());
4345
}
4446

4547
throw $exception;
48+
} finally {
49+
$connection = $entityManager->getConnection();
50+
51+
if (!$success && $connection->isTransactionActive()) {
52+
$connection->rollBack();
53+
}
4654
}
4755
}
4856
}

src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineTransactionMiddlewareTest.php

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,37 @@ public function testMiddlewareWrapsInTransactionAndFlushes()
5656

5757
public function testTransactionIsRolledBackOnException()
5858
{
59-
$this->connection->expects($this->once())
60-
->method('beginTransaction')
61-
;
62-
$this->connection->expects($this->once())
63-
->method('rollBack')
64-
;
59+
$this->connection->expects($this->once())->method('beginTransaction');
60+
$this->connection->expects($this->once())->method('isTransactionActive')->willReturn(true);
61+
$this->connection->expects($this->once())->method('rollBack');
6562

6663
$this->expectException(\RuntimeException::class);
6764
$this->expectExceptionMessage('Thrown from next middleware.');
6865

6966
$this->middleware->handle(new Envelope(new \stdClass()), $this->getThrowingStackMock());
7067
}
7168

69+
public function testExceptionInRollBackDoesNotHidePreviousException()
70+
{
71+
$this->connection->expects($this->once())->method('beginTransaction');
72+
$this->connection->expects($this->once())->method('isTransactionActive')->willReturn(true);
73+
$this->connection->expects($this->once())->method('rollBack')->willThrowException(new \RuntimeException('Thrown from rollBack.'));
74+
75+
try {
76+
$this->middleware->handle(new Envelope(new \stdClass()), $this->getThrowingStackMock());
77+
} catch (\Throwable $exception) {
78+
}
79+
80+
self::assertNotNull($exception);
81+
self::assertInstanceOf(\RuntimeException::class, $exception);
82+
self::assertSame('Thrown from rollBack.', $exception->getMessage());
83+
84+
$previous = $exception->getPrevious();
85+
self::assertNotNull($previous);
86+
self::assertInstanceOf(\RuntimeException::class, $previous);
87+
self::assertSame('Thrown from next middleware.', $previous->getMessage());
88+
}
89+
7290
public function testInvalidEntityManagerThrowsException()
7391
{
7492
$managerRegistry = $this->createMock(ManagerRegistry::class);

src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public function testGenerateFragmentUri()
8080
]);
8181
$twig->addRuntimeLoader($loader);
8282

83-
$this->assertSame('/_fragment?_hash=XCg0hX8QzSwik8Xuu9aMXhoCeI4oJOob7lUVacyOtyY&amp;_path=template%3Dfoo.html.twig%26_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CController%255CTemplateController%253A%253AtemplateAction', $twig->render('index'));
83+
$this->assertMatchesRegularExpression('#/_fragment\?_hash=.+&amp;_path=template%3Dfoo.html.twig%26_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CController%255CTemplateController%253A%253AtemplateAction$#', $twig->render('index'));
8484
}
8585

8686
protected function getFragmentHandler($returnOrException): FragmentHandler

src/Symfony/Bundle/FrameworkBundle/Command/TranslationExtractCommand.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ public function __construct(
6060
private array $enabledLocales = [],
6161
) {
6262
parent::__construct();
63+
64+
if (!method_exists($writer, 'getFormats')) {
65+
throw new \InvalidArgumentException(sprintf('The writer class "%s" does not implement the "getFormats()" method.', $writer::class));
66+
}
6367
}
6468

6569
protected function configure(): void
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\Translation\TranslatorBagInterface;
17+
use Symfony\Contracts\Translation\TranslatorInterface;
18+
19+
final class TranslationLintCommandPass implements CompilerPassInterface
20+
{
21+
public function process(ContainerBuilder $container): void
22+
{
23+
if (!$container->hasDefinition('console.command.translation_lint') || !$container->has('translator')) {
24+
return;
25+
}
26+
27+
$translatorClass = $container->getParameterBag()->resolveValue($container->findDefinition('translator')->getClass());
28+
29+
if (!is_subclass_of($translatorClass, TranslatorInterface::class) || !is_subclass_of($translatorClass, TranslatorBagInterface::class)) {
30+
$container->removeDefinition('console.command.translation_lint');
31+
}
32+
}
33+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
17+
class TranslationUpdateCommandPass implements CompilerPassInterface
18+
{
19+
public function process(ContainerBuilder $container): void
20+
{
21+
if (!$container->hasDefinition('console.command.translation_extract')) {
22+
return;
23+
}
24+
25+
$translationWriterClass = $container->getParameterBag()->resolveValue($container->findDefinition('translation.writer')->getClass());
26+
27+
if (!method_exists($translationWriterClass, 'getFormats')) {
28+
$container->removeDefinition('console.command.translation_extract');
29+
}
30+
}
31+
}

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@
126126
use Symfony\Component\Mime\MimeTypeGuesserInterface;
127127
use Symfony\Component\Mime\MimeTypes;
128128
use Symfony\Component\Notifier\Bridge as NotifierBridge;
129+
use Symfony\Component\Notifier\Bridge\FakeChat\FakeChatTransportFactory;
130+
use Symfony\Component\Notifier\Bridge\FakeSms\FakeSmsTransportFactory;
129131
use Symfony\Component\Notifier\ChatterInterface;
130132
use Symfony\Component\Notifier\Notifier;
131133
use Symfony\Component\Notifier\Recipient\Recipient;
@@ -2902,8 +2904,6 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $
29022904
NotifierBridge\Engagespot\EngagespotTransportFactory::class => 'notifier.transport_factory.engagespot',
29032905
NotifierBridge\Esendex\EsendexTransportFactory::class => 'notifier.transport_factory.esendex',
29042906
NotifierBridge\Expo\ExpoTransportFactory::class => 'notifier.transport_factory.expo',
2905-
NotifierBridge\FakeChat\FakeChatTransportFactory::class => 'notifier.transport_factory.fake-chat',
2906-
NotifierBridge\FakeSms\FakeSmsTransportFactory::class => 'notifier.transport_factory.fake-sms',
29072907
NotifierBridge\Firebase\FirebaseTransportFactory::class => 'notifier.transport_factory.firebase',
29082908
NotifierBridge\FortySixElks\FortySixElksTransportFactory::class => 'notifier.transport_factory.forty-six-elks',
29092909
NotifierBridge\FreeMobile\FreeMobileTransportFactory::class => 'notifier.transport_factory.free-mobile',
@@ -2991,20 +2991,26 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $
29912991
$container->removeDefinition($classToServices[NotifierBridge\Mercure\MercureTransportFactory::class]);
29922992
}
29932993

2994-
if (ContainerBuilder::willBeAvailable('symfony/fake-chat-notifier', NotifierBridge\FakeChat\FakeChatTransportFactory::class, ['symfony/framework-bundle', 'symfony/notifier', 'symfony/mailer'])) {
2995-
$container->getDefinition($classToServices[NotifierBridge\FakeChat\FakeChatTransportFactory::class])
2996-
->replaceArgument(0, new Reference('mailer'))
2997-
->replaceArgument(1, new Reference('logger'))
2994+
// don't use ContainerBuilder::willBeAvailable() as these are not needed in production
2995+
if (class_exists(FakeChatTransportFactory::class)) {
2996+
$container->getDefinition('notifier.transport_factory.fake-chat')
2997+
->replaceArgument(0, new Reference('mailer', ContainerBuilder::NULL_ON_INVALID_REFERENCE))
2998+
->replaceArgument(1, new Reference('logger', ContainerBuilder::NULL_ON_INVALID_REFERENCE))
29982999
->addArgument(new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE))
29993000
->addArgument(new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE));
3001+
} else {
3002+
$container->removeDefinition('notifier.transport_factory.fake-chat');
30003003
}
30013004

3002-
if (ContainerBuilder::willBeAvailable('symfony/fake-sms-notifier', NotifierBridge\FakeSms\FakeSmsTransportFactory::class, ['symfony/framework-bundle', 'symfony/notifier', 'symfony/mailer'])) {
3003-
$container->getDefinition($classToServices[NotifierBridge\FakeSms\FakeSmsTransportFactory::class])
3004-
->replaceArgument(0, new Reference('mailer'))
3005-
->replaceArgument(1, new Reference('logger'))
3005+
// don't use ContainerBuilder::willBeAvailable() as these are not needed in production
3006+
if (class_exists(FakeSmsTransportFactory::class)) {
3007+
$container->getDefinition('notifier.transport_factory.fake-sms')
3008+
->replaceArgument(0, new Reference('mailer', ContainerBuilder::NULL_ON_INVALID_REFERENCE))
3009+
->replaceArgument(1, new Reference('logger', ContainerBuilder::NULL_ON_INVALID_REFERENCE))
30063010
->addArgument(new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE))
30073011
->addArgument(new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE));
3012+
} else {
3013+
$container->removeDefinition('notifier.transport_factory.fake-sms');
30083014
}
30093015

30103016
if (ContainerBuilder::willBeAvailable('symfony/bluesky-notifier', NotifierBridge\Bluesky\BlueskyTransportFactory::class, ['symfony/framework-bundle', 'symfony/notifier'])) {

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RemoveUnusedSessionMarshallingHandlerPass;
2020
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerRealRefPass;
2121
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerWeakRefPass;
22+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationLintCommandPass;
23+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationUpdateCommandPass;
2224
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
2325
use Symfony\Bundle\FrameworkBundle\DependencyInjection\VirtualRequestStackPass;
2426
use Symfony\Component\Cache\Adapter\ApcuAdapter;
@@ -149,6 +151,8 @@ public function build(ContainerBuilder $container): void
149151
$this->addCompilerPassIfExists($container, AddConstraintValidatorsPass::class);
150152
$this->addCompilerPassIfExists($container, AddValidatorInitializersPass::class);
151153
$this->addCompilerPassIfExists($container, AddConsoleCommandPass::class, PassConfig::TYPE_BEFORE_REMOVING);
154+
// must be registered before the AddConsoleCommandPass
155+
$container->addCompilerPass(new TranslationLintCommandPass(), PassConfig::TYPE_BEFORE_REMOVING, 10);
152156
// must be registered as late as possible to get access to all Twig paths registered in
153157
// twig.template_iterator definition
154158
$this->addCompilerPassIfExists($container, TranslatorPass::class, PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
@@ -181,6 +185,7 @@ public function build(ContainerBuilder $container): void
181185
// must be registered after MonologBundle's LoggerChannelPass
182186
$container->addCompilerPass(new ErrorLoggerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
183187
$container->addCompilerPass(new VirtualRequestStackPass());
188+
$container->addCompilerPass(new TranslationUpdateCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
184189

185190
if ($container->getParameter('kernel.debug')) {
186191
$container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2);

src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ public function testGenerateFragmentUri()
5050
$client = self::createClient(['test_case' => 'Fragment', 'root_config' => 'config.yml', 'debug' => true]);
5151
$client->request('GET', '/fragment_uri');
5252

53-
$this->assertSame('/_fragment?_hash=CCRGN2D_oAJbeGz__doH3bNSPwLCrmwC1zAYCGIKJ0E&_path=_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CTests%255CFunctional%255CBundle%255CTestBundle%255CController%255CFragmentController%253A%253AindexAction', $client->getResponse()->getContent());
53+
$this->assertMatchesRegularExpression('#/_fragment\?_hash=.+&_path=_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CTests%255CFunctional%255CBundle%255CTestBundle%255CController%255CFragmentController%253A%253AindexAction$#', $client->getResponse()->getContent());
5454
}
5555
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy