Merge branch '4.3' into 4.4
* 4.3: [FWBundle] Remove unused parameter [Intl] [Workflow] fixes English grammar typos [Filesystem] [Serializer] fixes English grammar typo [Messenger] Adding exception to amqp transport in case amqp ext is not installed [Monolog Bridge] Fixed accessing static property as non static. Improve Symfony description Add DateTimeZoneNormalizer into Dependency Injection [Messenger] Error when specified default bus is not among the configured [Validator] Add Japanese translation [Workflow] Apply the same logic of precedence between the apply() and the buildTransitionBlockerList() method Remove some unused methods parameters Avoid empty \"If-Modified-Since\" header in validation request [Security] Fix SwitchUser is broken when the User Provider always returns a valid user Fix error message according to the new regex compatibility with DoctrineBundle 2 [Validator] ConstraintValidatorTestCase: add missing return value to mocked validate method calls
This commit is contained in:
commit
cde2538849
@ -2,7 +2,7 @@
|
||||
<img src="https://symfony.com/logos/symfony_black_02.svg">
|
||||
</a></p>
|
||||
|
||||
[Symfony][1] is a **PHP framework** for web applications and a set of reusable
|
||||
[Symfony][1] is a **PHP framework** for web and console applications and a set of reusable
|
||||
**PHP components**. Symfony is used by thousands of web applications (including
|
||||
BlaBlaCar.com and Spotify.com) and most of the [popular PHP projects][2] (including
|
||||
Drupal and Magento).
|
||||
|
@ -41,7 +41,7 @@ class ChromePhpHandler extends BaseChromePhpHandler
|
||||
}
|
||||
|
||||
if (!preg_match(static::USER_AGENT_REGEX, $event->getRequest()->headers->get('User-Agent'))) {
|
||||
$this->sendHeaders = false;
|
||||
self::$sendHeaders = false;
|
||||
$this->headers = [];
|
||||
|
||||
return;
|
||||
@ -59,7 +59,7 @@ class ChromePhpHandler extends BaseChromePhpHandler
|
||||
*/
|
||||
protected function sendHeader($header, $content)
|
||||
{
|
||||
if (!$this->sendHeaders) {
|
||||
if (!self::$sendHeaders) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ use Symfony\Component\Asset\Package;
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
@ -1173,6 +1174,10 @@ class Configuration implements ConfigurationInterface
|
||||
->ifTrue(function ($v) { return isset($v['buses']) && \count($v['buses']) > 1 && null === $v['default_bus']; })
|
||||
->thenInvalid('You must specify the "default_bus" if you define more than one bus.')
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(static function ($v): bool { return isset($v['buses']) && null !== $v['default_bus'] && !isset($v['buses'][$v['default_bus']]); })
|
||||
->then(static function (array $v): void { throw new InvalidConfigurationException(sprintf('The specified default bus "%s" is not configured. Available buses are "%s".', $v['default_bus'], implode('", "', array_keys($v['buses'])))); })
|
||||
->end()
|
||||
->children()
|
||||
->arrayNode('routing')
|
||||
->normalizeKeys(false)
|
||||
|
@ -304,7 +304,7 @@ class FrameworkExtension extends Extension
|
||||
}
|
||||
|
||||
if ($this->messengerConfigEnabled = $this->isConfigEnabled($container, $config['messenger'])) {
|
||||
$this->registerMessengerConfiguration($config['messenger'], $container, $loader, $config['serializer'], $config['validation']);
|
||||
$this->registerMessengerConfiguration($config['messenger'], $container, $loader, $config['validation']);
|
||||
} else {
|
||||
$container->removeDefinition('console.command.messenger_consume_messages');
|
||||
$container->removeDefinition('console.command.messenger_debug');
|
||||
@ -1696,7 +1696,7 @@ class FrameworkExtension extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
private function registerMessengerConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader, array $serializerConfig, array $validationConfig)
|
||||
private function registerMessengerConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader, array $validationConfig)
|
||||
{
|
||||
if (!interface_exists(MessageBusInterface::class)) {
|
||||
throw new LogicException('Messenger support cannot be enabled as the Messenger component is not installed. Try running "composer require symfony/messenger".');
|
||||
|
@ -40,6 +40,11 @@
|
||||
<tag name="serializer.normalizer" priority="-915" />
|
||||
</service>
|
||||
|
||||
<service id="serializer.normalizer.datetimezone" class="Symfony\Component\Serializer\Normalizer\DateTimeZoneNormalizer">
|
||||
<!-- Run before serializer.normalizer.object -->
|
||||
<tag name="serializer.normalizer" priority="-915" />
|
||||
</service>
|
||||
|
||||
<service id="serializer.normalizer.dateinterval" class="Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer">
|
||||
<!-- Run before serializer.normalizer.object -->
|
||||
<tag name="serializer.normalizer" priority="-915" />
|
||||
|
@ -329,6 +329,27 @@ class ConfigurationTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testItErrorsWhenDefaultBusDoesNotExist()
|
||||
{
|
||||
$processor = new Processor();
|
||||
$configuration = new Configuration(true);
|
||||
|
||||
$this->expectException(InvalidConfigurationException::class);
|
||||
$this->expectExceptionMessage('The specified default bus "foo" is not configured. Available buses are "bar", "baz".');
|
||||
|
||||
$processor->processConfiguration($configuration, [
|
||||
[
|
||||
'messenger' => [
|
||||
'default_bus' => 'foo',
|
||||
'buses' => [
|
||||
'bar' => null,
|
||||
'baz' => null,
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
protected static function getBundleDefaultConfig()
|
||||
{
|
||||
return [
|
||||
|
@ -121,7 +121,7 @@ EOF
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->displayLog($input, $output, $clientId, $record);
|
||||
$this->displayLog($output, $clientId, $record);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -150,7 +150,7 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
private function displayLog(InputInterface $input, OutputInterface $output, int $clientId, array $record)
|
||||
private function displayLog(OutputInterface $output, int $clientId, array $record)
|
||||
{
|
||||
if (isset($record['log_id'])) {
|
||||
$clientId = unpack('H*', $record['log_id'])[1];
|
||||
|
@ -797,7 +797,7 @@ class FilesystemTest extends FilesystemTestCase
|
||||
$file = $this->workspace.\DIRECTORY_SEPARATOR.'file';
|
||||
$link = $this->workspace.\DIRECTORY_SEPARATOR.'link';
|
||||
|
||||
// $file does not exists right now: creating "broken" links is a wanted feature
|
||||
// $file does not exist right now: creating "broken" links is a wanted feature
|
||||
$this->filesystem->symlink($file, $link);
|
||||
|
||||
$this->assertTrue(is_link($link));
|
||||
|
@ -63,7 +63,7 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
|
||||
|
||||
if (preg_match('/^([^a-zA-Z0-9_].*)?(.*[^a-zA-Z0-9_\-:].*)?$/D', $name, $matches)) {
|
||||
if (isset($matches[1])) {
|
||||
@trigger_error(sprintf('Using names for buttons that do not start with a lowercase letter, a digit, or an underscore is deprecated since Symfony 4.3 and will throw an exception in 5.0 ("%s" given).', $name), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('Using names for buttons that do not start with a letter, a digit, or an underscore is deprecated since Symfony 4.3 and will throw an exception in 5.0 ("%s" given).', $name), E_USER_DEPRECATED);
|
||||
}
|
||||
if (isset($matches[2])) {
|
||||
@trigger_error(sprintf('Using names for buttons that do not contain only letters, digits, underscores ("_"), hyphens ("-") and colons (":") ("%s" given) is deprecated since Symfony 4.3 and will throw an exception in 5.0.', $name), E_USER_DEPRECATED);
|
||||
|
@ -377,7 +377,9 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
|
||||
}
|
||||
|
||||
// add our cached last-modified validator
|
||||
if ($entry->headers->has('Last-Modified')) {
|
||||
$subRequest->headers->set('if_modified_since', $entry->headers->get('Last-Modified'));
|
||||
}
|
||||
|
||||
// Add our cached etag validator to the environment.
|
||||
// We keep the etags from the client to handle the case when the client
|
||||
|
@ -857,6 +857,7 @@ class HttpCacheTest extends HttpCacheTestCase
|
||||
public function testValidatesCachedResponsesWithETagAndNoFreshnessInformation()
|
||||
{
|
||||
$this->setNextResponse(200, [], 'Hello World', function ($request, $response) {
|
||||
$this->assertFalse($request->headers->has('If-Modified-Since'));
|
||||
$response->headers->set('Cache-Control', 'public');
|
||||
$response->headers->set('ETag', '"12345"');
|
||||
if ($response->getETag() == $request->headers->get('IF_NONE_MATCH')) {
|
||||
|
@ -46,7 +46,7 @@ final class Currencies extends ResourceBundle
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MissingResourceException if the currency code does not exists
|
||||
* @throws MissingResourceException if the currency code does not exist
|
||||
*/
|
||||
public static function getName(string $currency, string $displayLocale = null): string
|
||||
{
|
||||
@ -78,7 +78,7 @@ final class Currencies extends ResourceBundle
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MissingResourceException if the currency code does not exists
|
||||
* @throws MissingResourceException if the currency code does not exist
|
||||
*/
|
||||
public static function getSymbol(string $currency, string $displayLocale = null): string
|
||||
{
|
||||
@ -115,7 +115,7 @@ final class Currencies extends ResourceBundle
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MissingResourceException if the numeric code does not exists
|
||||
* @throws MissingResourceException if the numeric code does not exist
|
||||
*/
|
||||
public static function forNumericCode(int $numericCode): array
|
||||
{
|
||||
|
@ -49,7 +49,7 @@ final class Locales extends ResourceBundle
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MissingResourceException if the locale does not exists
|
||||
* @throws MissingResourceException if the locale does not exist
|
||||
*/
|
||||
public static function getName(string $locale, string $displayLocale = null): string
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ final class Scripts extends ResourceBundle
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MissingResourceException if the script code does not exists
|
||||
* @throws MissingResourceException if the script code does not exist
|
||||
*/
|
||||
public static function getName(string $script, string $displayLocale = null): string
|
||||
{
|
||||
|
@ -28,6 +28,9 @@ class AmqpTransportFactoryTest extends TestCase
|
||||
$this->assertFalse($factory->supports('invalid-dsn', []));
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires extension amqp
|
||||
*/
|
||||
public function testItCreatesTheTransport()
|
||||
{
|
||||
$factory = new AmqpTransportFactory();
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Messenger\Transport\AmqpExt;
|
||||
|
||||
use Symfony\Component\Messenger\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Messenger\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* An AMQP connection.
|
||||
@ -58,6 +59,10 @@ class Connection
|
||||
|
||||
public function __construct(array $connectionOptions, array $exchangeOptions, array $queuesOptions, AmqpFactory $amqpFactory = null)
|
||||
{
|
||||
if (!\extension_loaded('amqp')) {
|
||||
throw new LogicException(sprintf('You cannot use the "%s" as the "amqp" extension is not installed.', __CLASS__));
|
||||
}
|
||||
|
||||
$this->connectionOptions = array_replace_recursive([
|
||||
'delay' => [
|
||||
'exchange_name' => 'delays',
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Messenger\Transport\Doctrine;
|
||||
|
||||
use Doctrine\Common\Persistence\ConnectionRegistry;
|
||||
use Symfony\Bridge\Doctrine\RegistryInterface;
|
||||
use Symfony\Component\Messenger\Exception\TransportException;
|
||||
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
|
||||
use Symfony\Component\Messenger\Transport\TransportFactoryInterface;
|
||||
@ -24,8 +25,12 @@ class DoctrineTransportFactory implements TransportFactoryInterface
|
||||
{
|
||||
private $registry;
|
||||
|
||||
public function __construct(ConnectionRegistry $registry)
|
||||
public function __construct($registry)
|
||||
{
|
||||
if (!$registry instanceof RegistryInterface && !$registry instanceof ConnectionRegistry) {
|
||||
throw new \TypeError(sprintf('Expected an instance of %s or %s, but got %s.', RegistryInterface::class, ConnectionRegistry::class, \is_object($registry) ? \get_class($registry) : \gettype($registry)));
|
||||
}
|
||||
|
||||
$this->registry = $registry;
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,6 @@ class SwitchUserListener implements ListenerInterface
|
||||
|
||||
try {
|
||||
$this->provider->loadUserByUsername($nonExistentUsername);
|
||||
throw new \LogicException('AuthenticationException expected');
|
||||
} catch (AuthenticationException $e) {
|
||||
}
|
||||
} catch (AuthenticationException $e) {
|
||||
|
@ -27,7 +27,7 @@ trait ClassResolverTrait
|
||||
*
|
||||
* @param object|string $value
|
||||
*
|
||||
* @throws InvalidArgumentException If the class does not exists
|
||||
* @throws InvalidArgumentException If the class does not exist
|
||||
*/
|
||||
private function getClass($value): string
|
||||
{
|
||||
|
@ -362,6 +362,10 @@
|
||||
<source>This password has been leaked in a data breach, it must not be used. Please use another password.</source>
|
||||
<target>このパスワードは漏洩している為使用できません。</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="94">
|
||||
<source>This value should be between {{ min }} and {{ max }}.</source>
|
||||
<target>{{ min }}以上{{ max }}以下でなければなりません。</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
@ -179,7 +179,8 @@ abstract class ConstraintValidatorTestCase extends TestCase
|
||||
->willReturn($validator);
|
||||
$validator->expects($this->at(2 * $i + 1))
|
||||
->method('validate')
|
||||
->with($value, $this->logicalOr(null, [], $this->isInstanceOf('\Symfony\Component\Validator\Constraints\Valid')), $group);
|
||||
->with($value, $this->logicalOr(null, [], $this->isInstanceOf('\Symfony\Component\Validator\Constraints\Valid')), $group)
|
||||
->willReturn($validator);
|
||||
}
|
||||
|
||||
protected function expectValidateValueAt($i, $propertyPath, $value, $constraints, $group = null)
|
||||
@ -191,7 +192,8 @@ abstract class ConstraintValidatorTestCase extends TestCase
|
||||
->willReturn($contextualValidator);
|
||||
$contextualValidator->expects($this->at(2 * $i + 1))
|
||||
->method('validate')
|
||||
->with($value, $constraints, $group);
|
||||
->with($value, $constraints, $group)
|
||||
->willReturn($contextualValidator);
|
||||
}
|
||||
|
||||
protected function assertNoViolation()
|
||||
|
@ -51,7 +51,7 @@ final class MethodMarkingStore implements MarkingStoreInterface
|
||||
$method = 'get'.ucfirst($this->property);
|
||||
|
||||
if (!method_exists($subject, $method)) {
|
||||
throw new LogicException(sprintf('The method "%s::%s()" does not exists.', \get_class($subject), $method));
|
||||
throw new LogicException(sprintf('The method "%s::%s()" does not exist.', \get_class($subject), $method));
|
||||
}
|
||||
|
||||
$marking = $subject->{$method}();
|
||||
@ -81,7 +81,7 @@ final class MethodMarkingStore implements MarkingStoreInterface
|
||||
$method = 'set'.ucfirst($this->property);
|
||||
|
||||
if (!method_exists($subject, $method)) {
|
||||
throw new LogicException(sprintf('The method "%s::%s()" does not exists.', \get_class($subject), $method));
|
||||
throw new LogicException(sprintf('The method "%s::%s()" does not exist.', \get_class($subject), $method));
|
||||
}
|
||||
|
||||
$subject->{$method}($marking, $context);
|
||||
|
@ -5,6 +5,7 @@ namespace Symfony\Component\Workflow\Tests;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\Workflow\Event\GuardEvent;
|
||||
use Symfony\Component\Workflow\Exception\NotEnabledTransitionException;
|
||||
use Symfony\Component\Workflow\StateMachine;
|
||||
use Symfony\Component\Workflow\TransitionBlocker;
|
||||
|
||||
@ -84,27 +85,52 @@ class StateMachineTest extends TestCase
|
||||
$subject = new Subject();
|
||||
|
||||
// There may be multiple transitions with the same name. Make sure that transitions
|
||||
// that are not enabled by the marking are evaluated.
|
||||
// that are enabled by the marking are evaluated.
|
||||
// see https://github.com/symfony/symfony/issues/28432
|
||||
|
||||
// Test if when you are in place "a"trying transition "t1" then returned
|
||||
// Test if when you are in place "a" and trying to apply "t1" then it returns
|
||||
// blocker list contains guard blocker instead blockedByMarking
|
||||
$subject->setMarking('a');
|
||||
$transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1');
|
||||
$this->assertCount(1, $transitionBlockerList);
|
||||
$blockers = iterator_to_array($transitionBlockerList);
|
||||
|
||||
$this->assertSame('Transition blocker of place a', $blockers[0]->getMessage());
|
||||
$this->assertSame('blocker', $blockers[0]->getCode());
|
||||
|
||||
// Test if when you are in place "d" trying transition "t1" then
|
||||
// returned blocker list contains guard blocker instead blockedByMarking
|
||||
// Test if when you are in place "d" and trying to apply "t1" then
|
||||
// it returns blocker list contains guard blocker instead blockedByMarking
|
||||
$subject->setMarking('d');
|
||||
$transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1');
|
||||
$this->assertCount(1, $transitionBlockerList);
|
||||
$blockers = iterator_to_array($transitionBlockerList);
|
||||
|
||||
$this->assertSame('Transition blocker of place d', $blockers[0]->getMessage());
|
||||
$this->assertSame('blocker', $blockers[0]->getCode());
|
||||
}
|
||||
|
||||
public function testApplyReturnsExpectedReasonOnBranchMerge()
|
||||
{
|
||||
$definition = $this->createComplexStateMachineDefinition();
|
||||
|
||||
$dispatcher = new EventDispatcher();
|
||||
$net = new StateMachine($definition, null, $dispatcher);
|
||||
|
||||
$dispatcher->addListener('workflow.guard', function (GuardEvent $event) {
|
||||
$event->addTransitionBlocker(new TransitionBlocker(sprintf('Transition blocker of place %s', $event->getTransition()->getFroms()[0]), 'blocker'));
|
||||
});
|
||||
|
||||
$subject = new Subject();
|
||||
|
||||
// There may be multiple transitions with the same name. Make sure that all transitions
|
||||
// that are enabled by the marking are evaluated.
|
||||
// see https://github.com/symfony/symfony/issues/34489
|
||||
|
||||
try {
|
||||
$net->apply($subject, 't1');
|
||||
$this->fail();
|
||||
} catch (NotEnabledTransitionException $e) {
|
||||
$blockers = iterator_to_array($e->getTransitionBlockerList());
|
||||
$this->assertSame('Transition blocker of place a', $blockers[0]->getMessage());
|
||||
$this->assertSame('blocker', $blockers[0]->getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,25 +159,47 @@ class Workflow implements WorkflowInterface
|
||||
|
||||
$marking = $this->getMarking($subject);
|
||||
|
||||
$transitionBlockerList = null;
|
||||
$applied = false;
|
||||
$approvedTransitionQueue = [];
|
||||
$transitionExist = false;
|
||||
$approvedTransitions = [];
|
||||
$bestTransitionBlockerList = null;
|
||||
|
||||
foreach ($this->definition->getTransitions() as $transition) {
|
||||
if ($transition->getName() !== $transitionName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$transitionBlockerList = $this->buildTransitionBlockerListForTransition($subject, $marking, $transition);
|
||||
if (!$transitionBlockerList->isEmpty()) {
|
||||
$transitionExist = true;
|
||||
|
||||
$tmpTransitionBlockerList = $this->buildTransitionBlockerListForTransition($subject, $marking, $transition);
|
||||
|
||||
if ($tmpTransitionBlockerList->isEmpty()) {
|
||||
$approvedTransitions[] = $transition;
|
||||
continue;
|
||||
}
|
||||
$approvedTransitionQueue[] = $transition;
|
||||
|
||||
if (!$bestTransitionBlockerList) {
|
||||
$bestTransitionBlockerList = $tmpTransitionBlockerList;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($approvedTransitionQueue as $transition) {
|
||||
$applied = true;
|
||||
// We prefer to return transitions blocker by something else than
|
||||
// marking. Because it means the marking was OK. Transitions are
|
||||
// deterministic: it's not possible to have many transitions enabled
|
||||
// at the same time that match the same marking with the same name
|
||||
if (!$tmpTransitionBlockerList->has(TransitionBlocker::BLOCKED_BY_MARKING)) {
|
||||
$bestTransitionBlockerList = $tmpTransitionBlockerList;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$transitionExist) {
|
||||
throw new UndefinedTransitionException($subject, $transitionName, $this);
|
||||
}
|
||||
|
||||
if (!$approvedTransitions) {
|
||||
throw new NotEnabledTransitionException($subject, $transitionName, $this, $bestTransitionBlockerList);
|
||||
}
|
||||
|
||||
foreach ($approvedTransitions as $transition) {
|
||||
$this->leave($subject, $transition, $marking);
|
||||
|
||||
$context = $this->transition($subject, $transition, $marking, $context);
|
||||
@ -193,14 +215,6 @@ class Workflow implements WorkflowInterface
|
||||
$this->announce($subject, $transition, $marking);
|
||||
}
|
||||
|
||||
if (!$transitionBlockerList) {
|
||||
throw new UndefinedTransitionException($subject, $transitionName, $this);
|
||||
}
|
||||
|
||||
if (!$applied) {
|
||||
throw new NotEnabledTransitionException($subject, $transitionName, $this, $transitionBlockerList);
|
||||
}
|
||||
|
||||
return $marking;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user