Merge branch '4.3' into 4.4

* 4.3:
  [Form][Validator][Intl] Fix tests
  [Messenger] return empty envelopes when RetryableException occurs
  [Validator] Accept underscores in the URL validator as the URL will resolve correctly
  [Translation] Collect original locale in case of fallback translation
  Fix toolbar load when GET params are present in "_wdt" route
This commit is contained in:
Nicolas Grekas 2019-09-27 16:21:43 +02:00
commit 4acef47abb
11 changed files with 64 additions and 18 deletions

View File

@ -13,7 +13,7 @@
{% set text %}
<div class="sf-toolbar-info-piece">
<b>Locale</b>
<b>Default locale</b>
<span class="sf-toolbar-status">
{{ collector.locale|default('-') }}
</span>
@ -61,7 +61,7 @@
<div class="metrics">
<div class="metric">
<span class="value">{{ collector.locale|default('-') }}</span>
<span class="label">Locale</span>
<span class="label">Default locale</span>
</div>
<div class="metric">
<span class="value">{{ collector.fallbackLocales|join(', ')|default('-') }}</span>
@ -126,7 +126,7 @@
</div>
{% else %}
{% block fallback_messages %}
{{ helper.render_table(messages_fallback) }}
{{ helper.render_table(messages_fallback, true) }}
{% endblock %}
{% endif %}
</div>
@ -162,11 +162,14 @@
{% endblock %}
{% macro render_table(messages) %}
{% macro render_table(messages, is_fallback) %}
<table data-filters>
<thead>
<tr>
<th data-filter="locale">Locale</th>
{% if is_fallback %}
<th>Fallback locale</th>
{% endif %}
<th data-filter="domain">Domain</th>
<th>Times used</th>
<th>Message ID</th>
@ -177,6 +180,9 @@
{% for message in messages %}
<tr data-filter-locale="{{ message.locale }}" data-filter-domain="{{ message.domain }}">
<td class="font-normal text-small nowrap">{{ message.locale }}</td>
{% if is_fallback %}
<td class="font-normal text-small nowrap">{{ message.fallbackLocale|default('-') }}</td>
{% endif %}
<td class="font-normal text-small text-bold nowrap">{{ message.domain }}</td>
<td class="font-normal text-small nowrap">{{ message.count }}</td>
<td>

View File

@ -429,7 +429,7 @@
newToken = (newToken || token);
this.load(
'sfwdt' + token,
'{{ path("_wdt", { "token": "xxxxxx" }) }}'.replace(/xxxxxx/, newToken),
'{{ path("_wdt", { "token": "xxxxxx" })|escape('js') }}'.replace(/xxxxxx/, newToken),
function(xhr, el) {
/* Evaluate in global scope scripts embedded inside the toolbar */
@ -532,7 +532,7 @@
sfwdt.innerHTML = '\
<div class="sf-toolbarreset">\
<div class="sf-toolbar-icon"><svg width="26" height="28" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 26 28" enable-background="new 0 0 26 28" xml:space="preserve"><path fill="#FFFFFF" d="M13 0C5.8 0 0 5.8 0 13c0 7.2 5.8 13 13 13c7.2 0 13-5.8 13-13C26 5.8 20.2 0 13 0z M20 7.5 c-0.6 0-1-0.3-1-0.9c0-0.2 0-0.4 0.2-0.6c0.1-0.3 0.2-0.3 0.2-0.4c0-0.3-0.5-0.4-0.7-0.4c-2 0.1-2.5 2.7-2.9 4.8l-0.2 1.1 c1.1 0.2 1.9 0 2.4-0.3c0.6-0.4-0.2-0.8-0.1-1.3C18 9.2 18.4 9 18.7 8.9c0.5 0 0.8 0.5 0.8 1c0 0.8-1.1 2-3.3 1.9 c-0.3 0-0.5 0-0.7-0.1L15 14.1c-0.4 1.7-0.9 4.1-2.6 6.2c-1.5 1.8-3.1 2.1-3.8 2.1c-1.3 0-2.1-0.6-2.2-1.6c0-0.9 0.8-1.4 1.3-1.4 c0.7 0 1.2 0.5 1.2 1.1c0 0.5-0.2 0.6-0.4 0.7c-0.1 0.1-0.3 0.2-0.3 0.4c0 0.1 0.1 0.3 0.4 0.3c0.5 0 0.9-0.3 1.2-0.5 c1.3-1 1.7-2.9 2.4-6.2l0.1-0.8c0.2-1.1 0.5-2.3 0.8-3.5c-0.9-0.7-1.4-1.5-2.6-1.8c-0.8-0.2-1.3 0-1.7 0.4C8.4 10 8.6 10.7 9 11.1 l0.7 0.7c0.8 0.9 1.3 1.7 1.1 2.7c-0.3 1.6-2.1 2.8-4.3 2.1c-1.9-0.6-2.2-1.9-2-2.7c0.2-0.6 0.7-0.8 1.2-0.6 c0.5 0.2 0.7 0.8 0.6 1.3c0 0.1 0 0.1-0.1 0.3C6 15 5.9 15.2 5.9 15.3c-0.1 0.4 0.4 0.7 0.8 0.8c0.8 0.3 1.7-0.2 1.9-0.9 c0.2-0.6-0.2-1.1-0.4-1.2l-0.8-0.9c-0.4-0.4-1.2-1.5-0.8-2.8c0.2-0.5 0.5-1 0.9-1.4c1-0.7 2-0.8 3-0.6c1.3 0.4 1.9 1.2 2.8 1.9 c0.5-1.3 1.1-2.6 2-3.8c0.9-1 2-1.7 3.3-1.8C20 4.8 21 5.4 21 6.3C21 6.7 20.8 7.5 20 7.5z"/></svg></div>\
An error occurred while loading the web debug toolbar. <a href="{{ path("_profiler_home") }}' + newToken + '>Open the web profiler.</a>\
An error occurred while loading the web debug toolbar. <a href="{{ path("_profiler_home")|escape('js') }}' + newToken + '>Open the web profiler.</a>\
</div>\
';
sfwdt.setAttribute('class', 'sf-toolbar sf-error-toolbar');

View File

@ -32,8 +32,6 @@ class LanguageTypeTest extends BaseTypeTest
->createView()->vars['choices'];
$this->assertContainsEquals(new ChoiceView('en', 'en', 'English'), $choices);
$this->assertContainsEquals(new ChoiceView('en_GB', 'en_GB', 'British English'), $choices);
$this->assertContainsEquals(new ChoiceView('en_US', 'en_US', 'American English'), $choices);
$this->assertContainsEquals(new ChoiceView('fr', 'fr', 'French'), $choices);
$this->assertContainsEquals(new ChoiceView('my', 'my', 'Burmese'), $choices);
}
@ -51,7 +49,6 @@ class LanguageTypeTest extends BaseTypeTest
// Don't check objects for identity
$this->assertContainsEquals(new ChoiceView('en', 'en', 'англійська'), $choices);
$this->assertContainsEquals(new ChoiceView('en_US', 'en_US', 'англійська (США)'), $choices);
$this->assertContainsEquals(new ChoiceView('fr', 'fr', 'французька'), $choices);
$this->assertContainsEquals(new ChoiceView('my', 'my', 'бірманська'), $choices);
}

View File

@ -11,9 +11,12 @@
namespace Symfony\Component\Messenger\Tests\Transport\Doctrine;
use Doctrine\DBAL\Driver\PDOException;
use Doctrine\DBAL\Exception\DeadlockException;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
use Symfony\Component\Messenger\Exception\TransportException;
use Symfony\Component\Messenger\Stamp\TransportMessageIdStamp;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
use Symfony\Component\Messenger\Transport\Doctrine\Connection;
@ -68,6 +71,26 @@ class DoctrineReceiverTest extends TestCase
$receiver->get();
}
public function testOccursRetryableExceptionFromConnection()
{
$serializer = $this->createSerializer();
$connection = $this->createMock(Connection::class);
$driverException = new PDOException(new \PDOException('Deadlock', 40001));
$connection->method('get')->willThrowException(new DeadlockException('Deadlock', $driverException));
$receiver = new DoctrineReceiver($connection, $serializer);
$this->assertSame([], $receiver->get());
$this->assertSame([], $receiver->get());
try {
$receiver->get();
} catch (TransportException $exception) {
// skip, and retry
}
$this->assertSame([], $receiver->get());
$this->assertSame([], $receiver->get());
$this->expectException(TransportException::class);
$receiver->get();
}
public function testAll()
{
$serializer = $this->createSerializer();

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Messenger\Transport\Doctrine;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Exception\RetryableException;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\LogicException;
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
@ -28,6 +29,8 @@ use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
*/
class DoctrineReceiver implements ReceiverInterface, MessageCountAwareInterface, ListableReceiverInterface
{
private const MAX_RETRIES = 3;
private $retryingSafetyCounter = 0;
private $connection;
private $serializer;
@ -44,6 +47,17 @@ class DoctrineReceiver implements ReceiverInterface, MessageCountAwareInterface,
{
try {
$doctrineEnvelope = $this->connection->get();
$this->retryingSafetyCounter = 0; // reset counter
} catch (RetryableException $exception) {
// Do nothing when RetryableException occurs less than "MAX_RETRIES"
// as it will likely be resolved on the next call to get()
// Problem with concurrent consumers and database deadlocks
if (++$this->retryingSafetyCounter >= self::MAX_RETRIES) {
$this->retryingSafetyCounter = 0; // reset counter
throw new TransportException($exception->getMessage(), 0, $exception);
}
return [];
} catch (DBALException $exception) {
throw new TransportException($exception->getMessage(), 0, $exception);
}

View File

@ -20,7 +20,7 @@
"psr/log": "~1.0"
},
"require-dev": {
"doctrine/dbal": "^2.5",
"doctrine/dbal": "^2.6",
"psr/cache": "~1.0",
"doctrine/persistence": "~1.0",
"symfony/console": "^3.4|^4.0|^5.0",

View File

@ -150,6 +150,7 @@ class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorIn
$id = (string) $id;
$catalogue = $this->translator->getCatalogue($locale);
$locale = $catalogue->getLocale();
$fallbackLocale = null;
if ($catalogue->defines($id, $domain)) {
$state = self::MESSAGE_DEFINED;
} elseif ($catalogue->has($id, $domain)) {
@ -158,10 +159,9 @@ class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorIn
$fallbackCatalogue = $catalogue->getFallbackCatalogue();
while ($fallbackCatalogue) {
if ($fallbackCatalogue->defines($id, $domain)) {
$locale = $fallbackCatalogue->getLocale();
$fallbackLocale = $fallbackCatalogue->getLocale();
break;
}
$fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();
}
} else {
@ -170,6 +170,7 @@ class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorIn
$this->messages[] = [
'locale' => $locale,
'fallbackLocale' => $fallbackLocale,
'domain' => $domain,
'id' => $id,
'translation' => $translation,

View File

@ -34,6 +34,7 @@ class DataCollectorTranslatorTest extends TestCase
'id' => 'foo',
'translation' => 'foo (en)',
'locale' => 'en',
'fallbackLocale' => null,
'domain' => 'messages',
'state' => DataCollectorTranslator::MESSAGE_DEFINED,
'parameters' => [],
@ -42,7 +43,8 @@ class DataCollectorTranslatorTest extends TestCase
$expectedMessages[] = [
'id' => 'bar',
'translation' => 'bar (fr)',
'locale' => 'fr',
'locale' => 'en',
'fallbackLocale' => 'fr',
'domain' => 'messages',
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
'parameters' => [],
@ -52,6 +54,7 @@ class DataCollectorTranslatorTest extends TestCase
'id' => 'choice',
'translation' => 'choice',
'locale' => 'en',
'fallbackLocale' => null,
'domain' => 'messages',
'state' => DataCollectorTranslator::MESSAGE_MISSING,
'parameters' => ['%count%' => 0],
@ -60,7 +63,8 @@ class DataCollectorTranslatorTest extends TestCase
$expectedMessages[] = [
'id' => 'bar_ru',
'translation' => 'bar (ru)',
'locale' => 'ru',
'locale' => 'en',
'fallbackLocale' => 'ru',
'domain' => 'messages',
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
'parameters' => [],
@ -69,7 +73,8 @@ class DataCollectorTranslatorTest extends TestCase
$expectedMessages[] = [
'id' => 'bar_ru',
'translation' => 'bar (ru)',
'locale' => 'ru',
'locale' => 'en',
'fallbackLocale' => 'ru',
'domain' => 'messages',
'state' => DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK,
'parameters' => ['foo' => 'bar'],

View File

@ -26,7 +26,7 @@ class UrlValidator extends ConstraintValidator
(%s):// # protocol
(([\.\pL\pN-]+:)?([\.\pL\pN-]+)@)? # basic auth
(
([\pL\pN\pS\-\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name
([\pL\pN\pS\-\_\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name
| # or
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address
| # or

View File

@ -73,7 +73,6 @@ class LanguageValidatorTest extends ConstraintValidatorTestCase
{
return [
['en'],
['en_US'],
['my'],
];
}

View File

@ -106,6 +106,8 @@ class UrlValidatorTest extends ConstraintValidatorTestCase
['http://www.example.museum'],
['https://example.com/'],
['https://example.com:80/'],
['http://examp_le.com'],
['http://www.sub_domain.examp_le.com'],
['http://www.example.coop/'],
['http://www.test-example.com/'],
['http://www.symfony.com/'],
@ -239,7 +241,6 @@ class UrlValidatorTest extends ConstraintValidatorTestCase
['://example.com'],
['http ://example.com'],
['http:/example.com'],
['http://examp_le.com'],
['http://example.com::aa'],
['http://example.com:aa'],
['ftp://example.fr'],