Merge branch '4.4'

* 4.4: (27 commits)
  [Validator] add notice in UPGRADE file for new Range constraint option
  [CssSelector] Support *:only-of-type pseudo class selector
  [Intl] Update the ICU data to 65.1 (4.4 branch)
  [Intl] Update the ICU data to 65.1 (4.3 branch)
  Replace deprecated calls in tests
  [Intl] Update the ICU data to 65.1
  Delete 5_Security_issue.md
  [DI] Whitelist error_renderer.renderer tag  in UnusedTagsPass
  [DI] Whitelist validator.auto_mapper in UnusedTagsPass
  Update CHANGELOG.md
  [HttpClient] Fixed #33832 NO_PROXY option ignored in NativeHttpClient::request() method
  [EventDispatcher] A compiler pass for aliased userland events.
  [Cache] give 100ms before starting the expiration countdown
  [Cache] fix logger usage in CacheTrait::doGet()
  [VarDumper] fix dumping uninitialized SplFileInfo
  Added missing translations.
  [Form] Added CountryType option for using alpha3 country codes
  Fixed invalid changelog 4.0.0 for VarDumper
  [Workflow] Fixed BC break on WorkflowInterface
  Fix wrong expression language value
  ...
This commit is contained in:
Nicolas Grekas 2019-10-07 11:06:09 +02:00
commit e3e502ef6f
1281 changed files with 10451 additions and 7122 deletions

View File

@ -1,13 +0,0 @@
---
name: ⛔ Security Issue
about: See https://symfony.com/security to report security-related issues
---
⚠ PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, SEE BELOW.
If you have found a security issue in Symfony, please send the details to
security [at] symfony.com and don't disclose it publicly until we can provide a
fix for it.
More information: https://symfony.com/security

View File

@ -924,7 +924,7 @@ Validator
VarDumper VarDumper
--------- ---------
* The `VarDumperTestTrait::assertDumpEquals()` method expects a 3rd `$context = null` * The `VarDumperTestTrait::assertDumpEquals()` method expects a 3rd `$filter = 0`
argument and moves `$message = ''` argument at 4th position. argument and moves `$message = ''` argument at 4th position.
Before: Before:
@ -939,7 +939,7 @@ VarDumper
VarDumperTestTrait::assertDumpEquals($dump, $data, $filter = 0, $message = ''); VarDumperTestTrait::assertDumpEquals($dump, $data, $filter = 0, $message = '');
``` ```
* The `VarDumperTestTrait::assertDumpMatchesFormat()` method expects a 3rd `$context = null` * The `VarDumperTestTrait::assertDumpMatchesFormat()` method expects a 3rd `$filter = 0`
argument and moves `$message = ''` argument at 4th position. argument and moves `$message = ''` argument at 4th position.
Before: Before:

View File

@ -242,6 +242,28 @@ Workflow
initial_marking: [draft] initial_marking: [draft]
``` ```
* `WorkflowInterface::apply()` will have a third argument in Symfony 5.0.
Before:
```php
class MyWorkflow implements WorkflowInterface
{
public function apply($subject, $transitionName)
{
}
}
```
After:
```php
class MyWorkflow implements WorkflowInterface
{
public function apply($subject, $transitionName, array $context = [])
{
}
}
```
* `MarkingStoreInterface::setMarking()` will have a third argument in Symfony 5.0. * `MarkingStoreInterface::setMarking()` will have a third argument in Symfony 5.0.
Before: Before:

View File

@ -344,6 +344,8 @@ Validator
* Overriding the methods `ConstraintValidatorTestCase::setUp()` and `ConstraintValidatorTestCase::tearDown()` without the `void` return-type is deprecated. * Overriding the methods `ConstraintValidatorTestCase::setUp()` and `ConstraintValidatorTestCase::tearDown()` without the `void` return-type is deprecated.
* deprecated `Symfony\Component\Validator\Mapping\Cache\CacheInterface` and all implementations in favor of PSR-6. * deprecated `Symfony\Component\Validator\Mapping\Cache\CacheInterface` and all implementations in favor of PSR-6.
* deprecated `ValidatorBuilder::setMetadataCache`, use `ValidatorBuilder::setMappingCache` instead. * deprecated `ValidatorBuilder::setMetadataCache`, use `ValidatorBuilder::setMappingCache` instead.
* The `Range` constraint has a new message option `notInRangeMessage` that is used when both `min` and `max` values are set.
In case you are using custom translations make sure to add one for this new message.
WebProfilerBundle WebProfilerBundle
----------------- -----------------

View File

@ -611,6 +611,7 @@ Workflow
* `add` method has been removed use `addWorkflow` method in `Workflow\Registry` instead. * `add` method has been removed use `addWorkflow` method in `Workflow\Registry` instead.
* `SupportStrategyInterface` has been removed, use `WorkflowSupportStrategyInterface` instead. * `SupportStrategyInterface` has been removed, use `WorkflowSupportStrategyInterface` instead.
* `ClassInstanceSupportStrategy` has been removed, use `InstanceOfSupportStrategy` instead. * `ClassInstanceSupportStrategy` has been removed, use `InstanceOfSupportStrategy` instead.
* `WorkflowInterface::apply()` has a third argument: `array $context = []`.
* `MarkingStoreInterface::setMarking()` has a third argument: `array $context = []`. * `MarkingStoreInterface::setMarking()` has a third argument: `array $context = []`.
* Removed support of `initial_place`. Use `initial_places` instead. * Removed support of `initial_place`. Use `initial_places` instead.
* `MultipleStateMarkingStore` has been removed. Use `MethodMarkingStore` instead. * `MultipleStateMarkingStore` has been removed. Use `MethodMarkingStore` instead.

View File

@ -32,6 +32,7 @@ class UnusedTagsPass implements CompilerPassInterface
'controller.service_arguments', 'controller.service_arguments',
'config_cache.resource_checker', 'config_cache.resource_checker',
'data_collector', 'data_collector',
'error_renderer.renderer',
'form.type', 'form.type',
'form.type_extension', 'form.type_extension',
'form.type_guesser', 'form.type_guesser',
@ -63,6 +64,7 @@ class UnusedTagsPass implements CompilerPassInterface
'twig.loader', 'twig.loader',
'validator.constraint_validator', 'validator.constraint_validator',
'validator.initializer', 'validator.initializer',
'validator.auto_mapper',
]; ];
public function process(ContainerBuilder $container) public function process(ContainerBuilder $container)

View File

@ -23,10 +23,6 @@
<parameter key="Symfony\Component\HttpKernel\Event\ViewEvent">kernel.view</parameter> <parameter key="Symfony\Component\HttpKernel\Event\ViewEvent">kernel.view</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\ExceptionEvent">kernel.exception</parameter> <parameter key="Symfony\Component\HttpKernel\Event\ExceptionEvent">kernel.exception</parameter>
<parameter key="Symfony\Component\HttpKernel\Event\TerminateEvent">kernel.terminate</parameter> <parameter key="Symfony\Component\HttpKernel\Event\TerminateEvent">kernel.terminate</parameter>
<parameter key="Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent">security.authentication.success</parameter>
<parameter key="Symfony\Component\Security\Core\Event\AuthenticationFailureEvent">security.authentication.failure</parameter>
<parameter key="Symfony\Component\Security\Http\Event\InteractiveLoginEvent">security.interactive_login</parameter>
<parameter key="Symfony\Component\Security\Http\Event\SwitchUserEvent">security.switch_user</parameter>
<parameter key="Symfony\Component\Workflow\Event\GuardEvent">workflow.guard</parameter> <parameter key="Symfony\Component\Workflow\Event\GuardEvent">workflow.guard</parameter>
<parameter key="Symfony\Component\Workflow\Event\LeaveEvent">workflow.leave</parameter> <parameter key="Symfony\Component\Workflow\Event\LeaveEvent">workflow.leave</parameter>
<parameter key="Symfony\Component\Workflow\Event\TransitionEvent">workflow.transition</parameter> <parameter key="Symfony\Component\Workflow\Event\TransitionEvent">workflow.transition</parameter>

View File

@ -31,7 +31,14 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMe
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\LdapFactory; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\LdapFactory;
use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\EventDispatcher\DependencyInjection\AddEventAliasesPass;
use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
use Symfony\Component\Security\Http\SecurityEvents;
/** /**
* Bundle. * Bundle.
@ -64,5 +71,12 @@ class SecurityBundle extends Bundle
$container->addCompilerPass(new AddSessionDomainConstraintPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new AddSessionDomainConstraintPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new RegisterCsrfTokenClearingLogoutHandlerPass()); $container->addCompilerPass(new RegisterCsrfTokenClearingLogoutHandlerPass());
$container->addCompilerPass(new RegisterTokenUsageTrackingPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 200); $container->addCompilerPass(new RegisterTokenUsageTrackingPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 200);
$container->addCompilerPass(new AddEventAliasesPass([
AuthenticationSuccessEvent::class => AuthenticationEvents::AUTHENTICATION_SUCCESS,
AuthenticationFailureEvent::class => AuthenticationEvents::AUTHENTICATION_FAILURE,
InteractiveLoginEvent::class => SecurityEvents::INTERACTIVE_LOGIN,
SwitchUserEvent::class => SecurityEvents::SWITCH_USER,
]));
} }
} }

View File

@ -0,0 +1,26 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\EventBundle\DependencyInjection;
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\EventBundle\EventSubscriber\TestSubscriber;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
final class EventExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container): void
{
$container->register('test_subscriber', TestSubscriber::class)
->setPublic(true)
->addTag('kernel.event_subscriber');
}
}

View File

@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\EventBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
final class EventBundle extends Bundle
{
}

View File

@ -0,0 +1,38 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\EventBundle\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
final class TestSubscriber implements EventSubscriberInterface
{
public $calledMethods = [];
public static function getSubscribedEvents(): array
{
return [
AuthenticationSuccessEvent::class => 'onAuthenticationSuccess',
AuthenticationFailureEvent::class => 'onAuthenticationFailure',
InteractiveLoginEvent::class => 'onInteractiveLogin',
SwitchUserEvent::class => 'onSwitchUser',
];
}
public function __call(string $name, array $arguments)
{
$this->calledMethods[$name] = ($this->calledMethods[$name] ?? 0) + 1;
}
}

View File

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
use Symfony\Component\Security\Http\SecurityEvents;
final class EventAliasTest extends AbstractWebTestCase
{
public function testAliasedEvents(): void
{
$client = $this->createClient(['test_case' => 'AliasedEvents', 'root_config' => 'config.yml']);
$container = $client->getContainer();
$dispatcher = $container->get('event_dispatcher');
$dispatcher->dispatch(new AuthenticationSuccessEvent($this->createMock(TokenInterface::class)), AuthenticationEvents::AUTHENTICATION_SUCCESS);
$dispatcher->dispatch(new AuthenticationFailureEvent($this->createMock(TokenInterface::class), new AuthenticationException()), AuthenticationEvents::AUTHENTICATION_FAILURE);
$dispatcher->dispatch(new InteractiveLoginEvent($this->createMock(Request::class), $this->createMock(TokenInterface::class)), SecurityEvents::INTERACTIVE_LOGIN);
$dispatcher->dispatch(new SwitchUserEvent($this->createMock(Request::class), $this->createMock(UserInterface::class), $this->createMock(TokenInterface::class)), SecurityEvents::SWITCH_USER);
$this->assertEquals(
[
'onAuthenticationSuccess' => 1,
'onAuthenticationFailure' => 1,
'onInteractiveLogin' => 1,
'onSwitchUser' => 1,
],
$container->get('test_subscriber')->calledMethods
);
}
}

View File

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\EventBundle\EventBundle;
return [
new FrameworkBundle(),
new SecurityBundle(),
new EventBundle(),
];

View File

@ -0,0 +1,2 @@
imports:
- { resource: ./../config/framework.yml }

View File

@ -76,7 +76,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
$key = (string) $key; $key = (string) $key;
if (null === $item->expiry) { if (null === $item->expiry) {
$ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0; $ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0;
} elseif (0 >= $ttl = (int) ($item->expiry - $now)) { } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key); $expiredIds[] = $getId($key);
continue; continue;
} }
@ -84,7 +84,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
unset($metadata[CacheItem::METADATA_TAGS]); unset($metadata[CacheItem::METADATA_TAGS]);
} }
// For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators
$byLifetime[$ttl][$getId($key)] = $metadata ? ["\x9D".pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME])."\x5F" => $item->value] : $item->value; $byLifetime[$ttl][$getId($key)] = $metadata ? ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item->value] : $item->value;
} }
return $byLifetime; return $byLifetime;

View File

@ -81,7 +81,7 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
$key = (string) $key; $key = (string) $key;
if (null === $item->expiry) { if (null === $item->expiry) {
$ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0; $ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0;
} elseif (0 >= $ttl = (int) ($item->expiry - $now)) { } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key); $expiredIds[] = $getId($key);
continue; continue;
} }
@ -95,7 +95,7 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
if ($metadata) { if ($metadata) {
// For compactness, expiry and creation duration are packed, using magic numbers as separators // For compactness, expiry and creation duration are packed, using magic numbers as separators
$value['meta'] = pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME]); $value['meta'] = pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME]);
} }
// Extract tag changes, these should be removed from values in doSave() // Extract tag changes, these should be removed from values in doSave()

View File

@ -84,7 +84,7 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
} }
if ($metadata) { if ($metadata) {
// For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators
$item["\0*\0value"] = ["\x9D".pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME])."\x5F" => $item["\0*\0value"]]; $item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]];
} }
$innerItem->set($item["\0*\0value"]); $innerItem->set($item["\0*\0value"]);
$innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6f', $item["\0*\0expiry"])) : null); $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6f', $item["\0*\0expiry"])) : null);

View File

@ -177,7 +177,7 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
unset($metadata[CacheItem::METADATA_TAGS]); unset($metadata[CacheItem::METADATA_TAGS]);
if ($metadata) { if ($metadata) {
$values[$key] = ["\x9D".pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]]; $values[$key] = ["\x9D".pack('VN', (int) (0.1 + $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]];
} }
} }

View File

@ -109,7 +109,7 @@ abstract class AdapterTestCase extends CachePoolTest
$cache->deleteItem('foo'); $cache->deleteItem('foo');
$cache->get('foo', function ($item) { $cache->get('foo', function ($item) {
$item->expiresAfter(10); $item->expiresAfter(10);
sleep(1); usleep(999000);
return 'bar'; return 'bar';
}); });

View File

@ -61,7 +61,7 @@ trait ContractsTrait
static function (CacheItem $item, float $startTime, ?array &$metadata) { static function (CacheItem $item, float $startTime, ?array &$metadata) {
if ($item->expiry > $endTime = microtime(true)) { if ($item->expiry > $endTime = microtime(true)) {
$item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry; $item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
$item->newMetadata[CacheItem::METADATA_CTIME] = $metadata[CacheItem::METADATA_CTIME] = 1000 * (int) ($endTime - $startTime); $item->newMetadata[CacheItem::METADATA_CTIME] = $metadata[CacheItem::METADATA_CTIME] = (int) ceil(1000 * ($endTime - $startTime));
} else { } else {
unset($metadata[CacheItem::METADATA_EXPIRY], $metadata[CacheItem::METADATA_CTIME]); unset($metadata[CacheItem::METADATA_EXPIRY], $metadata[CacheItem::METADATA_CTIME]);
} }

View File

@ -1,6 +1,11 @@
CHANGELOG CHANGELOG
========= =========
4.4.0
-----
* Added support for `*:only-of-type`
2.8.0 2.8.0
----- -----

View File

@ -308,6 +308,8 @@ HTML
['li div:only-child', ['li-div']], ['li div:only-child', ['li-div']],
['div *:only-child', ['li-div', 'foobar-span']], ['div *:only-child', ['li-div', 'foobar-span']],
['p:only-of-type', ['paragraph']], ['p:only-of-type', ['paragraph']],
[':only-of-type', ['html', 'li-div', 'foobar-span', 'paragraph']],
['div#foobar-div :only-of-type', ['foobar-span']],
['a:empty', ['name-anchor']], ['a:empty', ['name-anchor']],
['a:EMpty', ['name-anchor']], ['a:EMpty', ['name-anchor']],
['li:empty', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li']], ['li:empty', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li']],

View File

@ -100,17 +100,10 @@ class PseudoClassExtension extends AbstractExtension
->addCondition('last() = 1'); ->addCondition('last() = 1');
} }
/**
* @throws ExpressionErrorException
*/
public function translateOnlyOfType(XPathExpr $xpath): XPathExpr public function translateOnlyOfType(XPathExpr $xpath): XPathExpr
{ {
$element = $xpath->getElement(); $element = $xpath->getElement();
if ('*' === $element) {
throw new ExpressionErrorException('"*:only-of-type" is not implemented.');
}
return $xpath->addCondition(sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element)); return $xpath->addCondition(sprintf('count(preceding-sibling::%s)=0 and count(following-sibling::%s)=0', $element, $element));
} }

View File

@ -24,12 +24,13 @@ class TaggedIteratorArgument extends IteratorArgument
private $needsIndexes = false; private $needsIndexes = false;
/** /**
* @param string $tag The name of the tag identifying the target services * @param string $tag The name of the tag identifying the target services
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute * @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
* @param bool $needsIndexes Whether indexes are required and should be generated when computing the map * @param bool $needsIndexes Whether indexes are required and should be generated when computing the map
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
*/ */
public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, bool $needsIndexes = false) public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, bool $needsIndexes = false, string $defaultPriorityMethod = null)
{ {
parent::__construct([]); parent::__construct([]);
@ -41,6 +42,7 @@ class TaggedIteratorArgument extends IteratorArgument
$this->indexAttribute = $indexAttribute; $this->indexAttribute = $indexAttribute;
$this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute ?? ''))).'Name'); $this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute ?? ''))).'Name');
$this->needsIndexes = $needsIndexes; $this->needsIndexes = $needsIndexes;
$this->defaultPriorityMethod = $defaultPriorityMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute ?? ''))).'Priority');
} }
public function getTag() public function getTag()
@ -62,4 +64,9 @@ class TaggedIteratorArgument extends IteratorArgument
{ {
return $this->needsIndexes; return $this->needsIndexes;
} }
public function getDefaultPriorityMethod(): ?string
{
return $this->defaultPriorityMethod;
}
} }

View File

@ -23,6 +23,7 @@ CHANGELOG
* deprecated passing an instance of `Symfony\Component\DependencyInjection\Parameter` as class name to `Symfony\Component\DependencyInjection\Definition` * deprecated passing an instance of `Symfony\Component\DependencyInjection\Parameter` as class name to `Symfony\Component\DependencyInjection\Definition`
* added support for binding iterable and tagged services * added support for binding iterable and tagged services
* made singly-implemented interfaces detection be scoped by file * made singly-implemented interfaces detection be scoped by file
* added ability to define a static priority method for tagged service
4.3.0 4.3.0
----- -----

View File

@ -40,19 +40,43 @@ trait PriorityTaggedServiceTrait
*/ */
private function findAndSortTaggedServices($tagName, ContainerBuilder $container): array private function findAndSortTaggedServices($tagName, ContainerBuilder $container): array
{ {
$indexAttribute = $defaultIndexMethod = $needsIndexes = null; $indexAttribute = $defaultIndexMethod = $needsIndexes = $defaultPriorityMethod = null;
if ($tagName instanceof TaggedIteratorArgument) { if ($tagName instanceof TaggedIteratorArgument) {
$indexAttribute = $tagName->getIndexAttribute(); $indexAttribute = $tagName->getIndexAttribute();
$defaultIndexMethod = $tagName->getDefaultIndexMethod(); $defaultIndexMethod = $tagName->getDefaultIndexMethod();
$needsIndexes = $tagName->needsIndexes(); $needsIndexes = $tagName->needsIndexes();
$defaultPriorityMethod = $tagName->getDefaultPriorityMethod();
$tagName = $tagName->getTag(); $tagName = $tagName->getTag();
} }
$services = []; $services = [];
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) { foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; $class = $r = null;
$priority = 0;
if (isset($attributes[0]['priority'])) {
$priority = $attributes[0]['priority'];
} elseif ($defaultPriorityMethod) {
$class = $container->getDefinition($serviceId)->getClass();
$class = $container->getParameterBag()->resolveValue($class) ?: null;
if (($r = $container->getReflectionClass($class)) && $r->hasMethod($defaultPriorityMethod)) {
if (!($rm = $r->getMethod($defaultPriorityMethod))->isStatic()) {
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
}
if (!$rm->isPublic()) {
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
}
$priority = $rm->invoke(null);
if (!\is_int($priority)) {
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return an integer, got %s: tag "%s" on service "%s".', $class, $defaultPriorityMethod, \gettype($priority), $tagName, $serviceId));
}
}
}
if (null === $indexAttribute && !$needsIndexes) { if (null === $indexAttribute && !$needsIndexes) {
$services[$priority][] = new Reference($serviceId); $services[$priority][] = new Reference($serviceId);
@ -60,8 +84,10 @@ trait PriorityTaggedServiceTrait
continue; continue;
} }
$class = $container->getDefinition($serviceId)->getClass(); if (!$class) {
$class = $container->getParameterBag()->resolveValue($class) ?: null; $class = $container->getDefinition($serviceId)->getClass();
$class = $container->getParameterBag()->resolveValue($class) ?: null;
}
if (null !== $indexAttribute && isset($attributes[0][$indexAttribute])) { if (null !== $indexAttribute && isset($attributes[0][$indexAttribute])) {
$services[$priority][$attributes[0][$indexAttribute]] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $attributes[0][$indexAttribute]); $services[$priority][$attributes[0][$indexAttribute]] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $attributes[0][$indexAttribute]);
@ -69,7 +95,7 @@ trait PriorityTaggedServiceTrait
continue; continue;
} }
if (!$r = $container->getReflectionClass($class)) { if (!$r && !$r = $container->getReflectionClass($class)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId)); throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId));
} }

View File

@ -274,6 +274,9 @@ class XmlDumper extends Dumper
if (null !== $tag->getDefaultIndexMethod()) { if (null !== $tag->getDefaultIndexMethod()) {
$element->setAttribute('default-index-method', $tag->getDefaultIndexMethod()); $element->setAttribute('default-index-method', $tag->getDefaultIndexMethod());
} }
if (null !== $tag->getDefaultPriorityMethod()) {
$element->setAttribute('default-priority-method', $tag->getDefaultPriorityMethod());
}
} }
} elseif ($value instanceof IteratorArgument) { } elseif ($value instanceof IteratorArgument) {
$element->setAttribute('type', 'iterator'); $element->setAttribute('type', 'iterator');

View File

@ -244,6 +244,9 @@ class YamlDumper extends Dumper
if (null !== $tag->getDefaultIndexMethod()) { if (null !== $tag->getDefaultIndexMethod()) {
$content['default_index_method'] = $tag->getDefaultIndexMethod(); $content['default_index_method'] = $tag->getDefaultIndexMethod();
} }
if (null !== $tag->getDefaultPriorityMethod()) {
$content['default_priority_method'] = $tag->getDefaultPriorityMethod();
}
} }
return new TaggedValue($value instanceof TaggedIteratorArgument ? 'tagged_iterator' : 'tagged_locator', $content); return new TaggedValue($value instanceof TaggedIteratorArgument ? 'tagged_iterator' : 'tagged_locator', $content);

View File

@ -116,9 +116,9 @@ function iterator(array $values): IteratorArgument
/** /**
* Creates a lazy iterator by tag name. * Creates a lazy iterator by tag name.
*/ */
function tagged_iterator(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null): TaggedIteratorArgument function tagged_iterator(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, string $defaultPriorityMethod = null): TaggedIteratorArgument
{ {
return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod); return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod);
} }
/** /**

View File

@ -510,7 +510,7 @@ class XmlFileLoader extends FileLoader
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="%s" has no or empty "tag" attribute in "%s".', $name, $type, $file)); throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="%s" has no or empty "tag" attribute in "%s".', $name, $type, $file));
} }
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null, $forLocator); $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null, $forLocator, $arg->getAttribute('default-priority-method') ?: null);
if ($forLocator) { if ($forLocator) {
$arguments[$key] = new ServiceLocatorArgument($arguments[$key]); $arguments[$key] = new ServiceLocatorArgument($arguments[$key]);

View File

@ -709,11 +709,11 @@ class YamlFileLoader extends FileLoader
$forLocator = 'tagged_locator' === $value->getTag(); $forLocator = 'tagged_locator' === $value->getTag();
if (\is_array($argument) && isset($argument['tag']) && $argument['tag']) { if (\is_array($argument) && isset($argument['tag']) && $argument['tag']) {
if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method'])) { if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method', 'default_priority_method'])) {
throw new InvalidArgumentException(sprintf('"!%s" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', $value->getTag(), implode('"", "', $diff))); throw new InvalidArgumentException(sprintf('"!%s" tag contains unsupported key "%s"; supported ones are "tag", "index_by", "default_index_method", and "default_priority_method".', $value->getTag(), implode('"", "', $diff)));
} }
$argument = new TaggedIteratorArgument($argument['tag'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null, $forLocator); $argument = new TaggedIteratorArgument($argument['tag'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null, $forLocator, $argument['default_priority_method'] ?? null);
} elseif (\is_string($argument) && $argument) { } elseif (\is_string($argument) && $argument) {
$argument = new TaggedIteratorArgument($argument, null, null, $forLocator); $argument = new TaggedIteratorArgument($argument, null, null, $forLocator);
} else { } else {

View File

@ -236,6 +236,7 @@
<xsd:attribute name="tag" type="xsd:string" /> <xsd:attribute name="tag" type="xsd:string" />
<xsd:attribute name="index-by" type="xsd:string" /> <xsd:attribute name="index-by" type="xsd:string" />
<xsd:attribute name="default-index-method" type="xsd:string" /> <xsd:attribute name="default-index-method" type="xsd:string" />
<xsd:attribute name="default-priority-method" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
<xsd:complexType name="call"> <xsd:complexType name="call">

View File

@ -22,6 +22,7 @@ use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarTagClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\BarTagClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedForDefaultPriorityClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooTagClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooTagClass;
use Symfony\Contracts\Service\ServiceSubscriberInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface;
@ -289,6 +290,30 @@ class IntegrationTest extends TestCase
$this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param); $this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param);
} }
public function testTaggedServiceWithDefaultPriorityMethod()
{
$container = new ContainerBuilder();
$container->register(BarTagClass::class)
->setPublic(true)
->addTag('foo_bar')
;
$container->register(FooTagClass::class)
->setPublic(true)
->addTag('foo_bar', ['foo' => 'foo'])
;
$container->register(FooBarTaggedForDefaultPriorityClass::class)
->addArgument(new TaggedIteratorArgument('foo_bar', null, null, false, 'getPriority'))
->setPublic(true)
;
$container->compile();
$s = $container->get(FooBarTaggedForDefaultPriorityClass::class);
$param = iterator_to_array($s->getParam()->getIterator());
$this->assertSame([$container->get(FooTagClass::class), $container->get(BarTagClass::class)], $param);
}
public function testTaggedServiceLocatorWithIndexAttribute() public function testTaggedServiceLocatorWithIndexAttribute()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();

View File

@ -204,7 +204,7 @@ class XmlDumperTest extends TestCase
public function testTaggedArguments() public function testTaggedArguments()
{ {
$taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'); $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar', false, 'getPriority');
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('foo', 'Foo')->addTag('foo_tag'); $container->register('foo', 'Foo')->addTag('foo_tag');
$container->register('foo_tagged_iterator', 'Bar') $container->register('foo_tagged_iterator', 'Bar')

View File

@ -99,7 +99,7 @@ class YamlDumperTest extends TestCase
public function testTaggedArguments() public function testTaggedArguments()
{ {
$taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar'); $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar', false, 'getPriority');
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('foo_service', 'Foo')->addTag('foo'); $container->register('foo_service', 'Foo')->addTag('foo');
$container->register('foo_service_tagged_iterator', 'Bar')->addArgument($taggedIterator); $container->register('foo_service_tagged_iterator', 'Bar')->addArgument($taggedIterator);

View File

@ -13,4 +13,9 @@ class BarTagClass
{ {
return 'bar_tab_class_with_defaultmethod'; return 'bar_tab_class_with_defaultmethod';
} }
public static function getPriority(): int
{
return 0;
}
} }

View File

@ -0,0 +1,18 @@
<?php
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
class FooBarTaggedForDefaultPriorityClass
{
private $param;
public function __construct($param = [])
{
$this->param = $param;
}
public function getParam()
{
return $this->param;
}
}

View File

@ -8,4 +8,11 @@ class FooTagClass
{ {
return 'foo_tag_class'; return 'foo_tag_class';
} }
public static function getPriority(): int
{
// Should be more than BarTagClass. More because this class is after
// BarTagClass (order by name). So we want to ensure it will be before it
return 20;
}
} }

View File

@ -6,10 +6,10 @@
<tag name="foo_tag"/> <tag name="foo_tag"/>
</service> </service>
<service id="foo_tagged_iterator" class="Bar" public="true"> <service id="foo_tagged_iterator" class="Bar" public="true">
<argument type="tagged_iterator" tag="foo_tag" index-by="barfoo" default-index-method="foobar"/> <argument type="tagged_iterator" tag="foo_tag" index-by="barfoo" default-index-method="foobar" default-priority-method="getPriority"/>
</service> </service>
<service id="foo_tagged_locator" class="Bar" public="true"> <service id="foo_tagged_locator" class="Bar" public="true">
<argument type="tagged_locator" tag="foo_tag" index-by="barfoo" default-index-method="foobar"/> <argument type="tagged_locator" tag="foo_tag" index-by="barfoo" default-index-method="foobar" default-priority-method="getPriority"/>
</service> </service>
<service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/> <service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/>
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/> <service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>

View File

@ -10,10 +10,10 @@ services:
- { name: foo } - { name: foo }
foo_service_tagged_iterator: foo_service_tagged_iterator:
class: Bar class: Bar
arguments: [!tagged_iterator { tag: foo, index_by: barfoo, default_index_method: foobar }] arguments: [!tagged_iterator { tag: foo, index_by: barfoo, default_index_method: foobar, default_priority_method: getPriority }]
foo_service_tagged_locator: foo_service_tagged_locator:
class: Bar class: Bar
arguments: [!tagged_locator { tag: foo, index_by: barfoo, default_index_method: foobar }] arguments: [!tagged_locator { tag: foo, index_by: barfoo, default_index_method: foobar, default_priority_method: getPriority }]
bar_service_tagged_locator: bar_service_tagged_locator:
class: Bar class: Bar
arguments: [!tagged_locator foo] arguments: [!tagged_locator foo]

View File

@ -327,10 +327,10 @@ class XmlFileLoaderTest extends TestCase
$this->assertCount(1, $container->getDefinition('foo_tagged_iterator')->getArguments()); $this->assertCount(1, $container->getDefinition('foo_tagged_iterator')->getArguments());
$this->assertCount(1, $container->getDefinition('foo_tagged_locator')->getArguments()); $this->assertCount(1, $container->getDefinition('foo_tagged_locator')->getArguments());
$taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'); $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar', false, 'getPriority');
$this->assertEquals($taggedIterator, $container->getDefinition('foo_tagged_iterator')->getArgument(0)); $this->assertEquals($taggedIterator, $container->getDefinition('foo_tagged_iterator')->getArgument(0));
$taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar', true); $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar', true, 'getPriority');
$this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_tagged_locator')->getArgument(0)); $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_tagged_locator')->getArgument(0));
} }

View File

@ -277,10 +277,10 @@ class YamlFileLoaderTest extends TestCase
$this->assertCount(1, $container->getDefinition('foo_service_tagged_iterator')->getArguments()); $this->assertCount(1, $container->getDefinition('foo_service_tagged_iterator')->getArguments());
$this->assertCount(1, $container->getDefinition('foo_service_tagged_locator')->getArguments()); $this->assertCount(1, $container->getDefinition('foo_service_tagged_locator')->getArguments());
$taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar'); $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar', false, 'getPriority');
$this->assertEquals($taggedIterator, $container->getDefinition('foo_service_tagged_iterator')->getArgument(0)); $this->assertEquals($taggedIterator, $container->getDefinition('foo_service_tagged_iterator')->getArgument(0));
$taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar', true); $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar', true, 'getPriority');
$this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_service_tagged_locator')->getArgument(0)); $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_service_tagged_locator')->getArgument(0));
$taggedIterator = new TaggedIteratorArgument('foo', null, null, true); $taggedIterator = new TaggedIteratorArgument('foo', null, null, true);

View File

@ -9,6 +9,11 @@ CHANGELOG
* The `TraceableEventDispatcherInterface` has been removed. * The `TraceableEventDispatcherInterface` has been removed.
* The `WrappedListener` class is now final. * The `WrappedListener` class is now final.
4.4.0
-----
* `AddEventAliasesPass` has been added, allowing applications and bundles to extend the event alias mapping used by `RegisterListenersPass`.
4.3.0 4.3.0
----- -----
@ -18,7 +23,7 @@ CHANGELOG
4.1.0 4.1.0
----- -----
* added support for invokable event listeners tagged with `kernel.event_listener` by default * added support for invokable event listeners tagged with `kernel.event_listener` by default
* The `TraceableEventDispatcher::getOrphanedEvents()` method has been added. * The `TraceableEventDispatcher::getOrphanedEvents()` method has been added.
* The `TraceableEventDispatcherInterface` has been deprecated. * The `TraceableEventDispatcherInterface` has been deprecated.

View File

@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\EventDispatcher\DependencyInjection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* This pass allows bundles to extend the list of event aliases.
*
* @author Alexander M. Turek <me@derrabus.de>
*/
class AddEventAliasesPass implements CompilerPassInterface
{
private $eventAliases;
private $eventAliasesParameter;
public function __construct(array $eventAliases, string $eventAliasesParameter = 'event_dispatcher.event_aliases')
{
$this->eventAliases = $eventAliases;
$this->eventAliasesParameter = $eventAliasesParameter;
}
public function process(ContainerBuilder $container): void
{
$eventAliases = $container->hasParameter($this->eventAliasesParameter) ? $container->getParameter($this->eventAliasesParameter) : [];
$container->setParameter(
$this->eventAliasesParameter,
array_merge($eventAliases, $this->eventAliases)
);
}
}

View File

@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\DependencyInjection\AddEventAliasesPass;
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@ -67,6 +68,9 @@ class RegisterListenersPassTest extends TestCase
$builder->register('my_event_subscriber', AliasedSubscriber::class) $builder->register('my_event_subscriber', AliasedSubscriber::class)
->addTag('kernel.event_subscriber'); ->addTag('kernel.event_subscriber');
$eventAliasPass = new AddEventAliasesPass([CustomEvent::class => 'custom_event']);
$eventAliasPass->process($builder);
$registerListenersPass = new RegisterListenersPass(); $registerListenersPass = new RegisterListenersPass();
$registerListenersPass->process($builder); $registerListenersPass->process($builder);
@ -79,6 +83,14 @@ class RegisterListenersPassTest extends TestCase
0, 0,
], ],
], ],
[
'addListener',
[
'custom_event',
[new ServiceClosureArgument(new Reference('my_event_subscriber')), 'onCustomEvent'],
0,
],
],
]; ];
$this->assertEquals($expectedCalls, $builder->getDefinition('event_dispatcher')->getMethodCalls()); $this->assertEquals($expectedCalls, $builder->getDefinition('event_dispatcher')->getMethodCalls());
} }
@ -202,8 +214,12 @@ class RegisterListenersPassTest extends TestCase
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->setParameter('event_dispatcher.event_aliases', [AliasedEvent::class => 'aliased_event']); $container->setParameter('event_dispatcher.event_aliases', [AliasedEvent::class => 'aliased_event']);
$container->register('foo', InvokableListenerService::class)->addTag('kernel.event_listener', ['event' => AliasedEvent::class, 'method' => 'onEvent']); $container->register('foo', InvokableListenerService::class)->addTag('kernel.event_listener', ['event' => AliasedEvent::class, 'method' => 'onEvent']);
$container->register('bar', InvokableListenerService::class)->addTag('kernel.event_listener', ['event' => CustomEvent::class, 'method' => 'onEvent']);
$container->register('event_dispatcher'); $container->register('event_dispatcher');
$eventAliasPass = new AddEventAliasesPass([CustomEvent::class => 'custom_event']);
$eventAliasPass->process($container);
$registerListenersPass = new RegisterListenersPass(); $registerListenersPass = new RegisterListenersPass();
$registerListenersPass->process($container); $registerListenersPass->process($container);
@ -217,6 +233,14 @@ class RegisterListenersPassTest extends TestCase
0, 0,
], ],
], ],
[
'addListener',
[
'custom_event',
[new ServiceClosureArgument(new Reference('bar')), 'onEvent'],
0,
],
],
]; ];
$this->assertEquals($expectedCalls, $definition->getMethodCalls()); $this->assertEquals($expectedCalls, $definition->getMethodCalls());
} }
@ -249,6 +273,7 @@ final class AliasedSubscriber implements EventSubscriberInterface
{ {
return [ return [
AliasedEvent::class => 'onAliasedEvent', AliasedEvent::class => 'onAliasedEvent',
CustomEvent::class => 'onCustomEvent',
]; ];
} }
} }
@ -256,3 +281,7 @@ final class AliasedSubscriber implements EventSubscriberInterface
final class AliasedEvent final class AliasedEvent
{ {
} }
final class CustomEvent
{
}

View File

@ -33,6 +33,7 @@ CHANGELOG
* Overriding the methods `FormIntegrationTestCase::setUp()`, `TypeTestCase::setUp()` and `TypeTestCase::tearDown()` without the `void` return-type is deprecated. * Overriding the methods `FormIntegrationTestCase::setUp()`, `TypeTestCase::setUp()` and `TypeTestCase::tearDown()` without the `void` return-type is deprecated.
* marked all dispatched event classes as `@final` * marked all dispatched event classes as `@final`
* Added the `validate` option to `SubmitType` to toggle the browser built-in form validation. * Added the `validate` option to `SubmitType` to toggle the browser built-in form validation.
* Added the `alpha3` option to `LanguageType` and `CountryType` to use alpha3 instead of alpha2 codes
4.3.0 4.3.0
----- -----

View File

@ -156,7 +156,7 @@ EOF
return 0; return 0;
} }
private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, string $shortClassName) private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, string $shortClassName): string
{ {
$classes = []; $classes = [];
sort($this->namespaces); sort($this->namespaces);
@ -197,7 +197,7 @@ EOF
return $io->choice(sprintf("The type \"%s\" is ambiguous.\n\nSelect one of the following form types to display its information:", $shortClassName), $classes, $classes[0]); return $io->choice(sprintf("The type \"%s\" is ambiguous.\n\nSelect one of the following form types to display its information:", $shortClassName), $classes, $classes[0]);
} }
private function getCoreTypes() private function getCoreTypes(): array
{ {
$coreExtension = new CoreExtension(); $coreExtension = new CoreExtension();
$loadTypesRefMethod = (new \ReflectionObject($coreExtension))->getMethod('loadTypes'); $loadTypesRefMethod = (new \ReflectionObject($coreExtension))->getMethod('loadTypes');
@ -225,7 +225,7 @@ EOF
return $typesWithDeprecatedOptions; return $typesWithDeprecatedOptions;
} }
private function findAlternatives(string $name, array $collection) private function findAlternatives(string $name, array $collection): array
{ {
$alternatives = []; $alternatives = [];
foreach ($collection as $item) { foreach ($collection as $item) {

View File

@ -167,7 +167,7 @@ abstract class Descriptor implements DescriptorInterface
$this->extensionOptions = $filterByDeprecated($this->extensionOptions); $this->extensionOptions = $filterByDeprecated($this->extensionOptions);
} }
private function getParentOptionsResolver(ResolvedFormTypeInterface $type) private function getParentOptionsResolver(ResolvedFormTypeInterface $type): OptionsResolver
{ {
$this->parents[$class = \get_class($type->getInnerType())] = []; $this->parents[$class = \get_class($type->getInnerType())] = [];

View File

@ -155,7 +155,7 @@ class TextDescriptor extends Descriptor
return $tableRows; return $tableRows;
} }
private function normalizeAndSortOptionsColumns(array $options) private function normalizeAndSortOptionsColumns(array $options): array
{ {
foreach ($options as $group => $opts) { foreach ($options as $group => $opts) {
$sorted = false; $sorted = false;

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Form\DependencyInjection; namespace Symfony\Component\Form\DependencyInjection;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
@ -59,7 +60,7 @@ class FormPass implements CompilerPassInterface
$definition->replaceArgument(2, $this->processFormTypeGuessers($container)); $definition->replaceArgument(2, $this->processFormTypeGuessers($container));
} }
private function processFormTypes(ContainerBuilder $container) private function processFormTypes(ContainerBuilder $container): Reference
{ {
// Get service locator argument // Get service locator argument
$servicesMap = []; $servicesMap = [];
@ -82,7 +83,7 @@ class FormPass implements CompilerPassInterface
return ServiceLocatorTagPass::register($container, $servicesMap); return ServiceLocatorTagPass::register($container, $servicesMap);
} }
private function processFormTypeExtensions(ContainerBuilder $container) private function processFormTypeExtensions(ContainerBuilder $container): array
{ {
$typeExtensions = []; $typeExtensions = [];
$typeExtensionsClasses = []; $typeExtensionsClasses = [];
@ -123,7 +124,7 @@ class FormPass implements CompilerPassInterface
return $typeExtensions; return $typeExtensions;
} }
private function processFormTypeGuessers(ContainerBuilder $container) private function processFormTypeGuessers(ContainerBuilder $container): ArgumentInterface
{ {
$guessers = []; $guessers = [];
$guessersClasses = []; $guessersClasses = [];

View File

@ -94,7 +94,7 @@ class DateIntervalToStringTransformer implements DataTransformerInterface
return $dateInterval; return $dateInterval;
} }
private function isISO8601(string $string) private function isISO8601(string $string): bool
{ {
return preg_match('/^P(?=\w*(?:\d|%\w))(?:\d+Y|%[yY]Y)?(?:\d+M|%[mM]M)?(?:(?:\d+D|%[dD]D)|(?:\d+W|%[wW]W))?(?:T(?:\d+H|[hH]H)?(?:\d+M|[iI]M)?(?:\d+S|[sS]S)?)?$/', $string); return preg_match('/^P(?=\w*(?:\d|%\w))(?:\d+Y|%[yY]Y)?(?:\d+M|%[mM]M)?(?:(?:\d+D|%[dD]D)|(?:\d+W|%[wW]W))?(?:T(?:\d+H|[hH]H)?(?:\d+M|[iI]M)?(?:\d+S|[sS]S)?)?$/', $string);
} }

View File

@ -27,16 +27,19 @@ class CountryType extends AbstractType
$resolver->setDefaults([ $resolver->setDefaults([
'choice_loader' => function (Options $options) { 'choice_loader' => function (Options $options) {
$choiceTranslationLocale = $options['choice_translation_locale']; $choiceTranslationLocale = $options['choice_translation_locale'];
$alpha3 = $options['alpha3'];
return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $alpha3) {
return array_flip(Countries::getNames($choiceTranslationLocale)); return array_flip($alpha3 ? Countries::getAlpha3Names($choiceTranslationLocale) : Countries::getNames($choiceTranslationLocale));
}); });
}, },
'choice_translation_domain' => false, 'choice_translation_domain' => false,
'choice_translation_locale' => null, 'choice_translation_locale' => null,
'alpha3' => false,
]); ]);
$resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']); $resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']);
$resolver->setAllowedTypes('alpha3', 'bool');
} }
/** /**

View File

@ -27,16 +27,19 @@ class LanguageType extends AbstractType
$resolver->setDefaults([ $resolver->setDefaults([
'choice_loader' => function (Options $options) { 'choice_loader' => function (Options $options) {
$choiceTranslationLocale = $options['choice_translation_locale']; $choiceTranslationLocale = $options['choice_translation_locale'];
$alpha3 = $options['alpha3'];
return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $alpha3) {
return array_flip(Languages::getNames($choiceTranslationLocale)); return array_flip($alpha3 ? Languages::getAlpha3Names($choiceTranslationLocale) : Languages::getNames($choiceTranslationLocale));
}); });
}, },
'choice_translation_domain' => false, 'choice_translation_domain' => false,
'choice_translation_locale' => null, 'choice_translation_locale' => null,
'alpha3' => false,
]); ]);
$resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']); $resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']);
$resolver->setAllowedTypes('alpha3', 'bool');
} }
/** /**

View File

@ -188,7 +188,7 @@ class FormValidator extends ConstraintValidator
* *
* @param string|GroupSequence|(string|GroupSequence)[]|callable $groups The validation groups * @param string|GroupSequence|(string|GroupSequence)[]|callable $groups The validation groups
* *
* @return (string|GroupSequence)[] The validation groups * @return GroupSequence|(string|GroupSequence)[] The validation groups
*/ */
private static function resolveValidationGroups($groups, FormInterface $form) private static function resolveValidationGroups($groups, FormInterface $form)
{ {

View File

@ -288,7 +288,7 @@ class FormRenderer implements FormRendererInterface
/** /**
* @internal * @internal
*/ */
public function encodeCurrency(Environment $environment, string $text, string $widget = '') public function encodeCurrency(Environment $environment, string $text, string $widget = ''): string
{ {
if ('UTF-8' === $charset = $environment->getCharset()) { if ('UTF-8' === $charset = $environment->getCharset()) {
$text = htmlspecialchars($text, ENT_QUOTES | (\defined('ENT_SUBSTITUTE') ? ENT_SUBSTITUTE : 0), 'UTF-8'); $text = htmlspecialchars($text, ENT_QUOTES | (\defined('ENT_SUBSTITUTE') ? ENT_SUBSTITUTE : 0), 'UTF-8');

View File

@ -57,6 +57,42 @@ class CountryTypeTest extends BaseTypeTest
$this->assertContainsEquals(new ChoiceView('MY', 'MY', 'Малайзія'), $choices); $this->assertContainsEquals(new ChoiceView('MY', 'MY', 'Малайзія'), $choices);
} }
public function testAlpha3Option()
{
$choices = $this->factory
->create(static::TESTED_TYPE, null, [
'alpha3' => true,
])
->createView()->vars['choices'];
// Don't check objects for identity
$this->assertContainsEquals(new ChoiceView('DEU', 'DEU', 'Germany'), $choices);
$this->assertContainsEquals(new ChoiceView('GBR', 'GBR', 'United Kingdom'), $choices);
$this->assertContainsEquals(new ChoiceView('USA', 'USA', 'United States'), $choices);
$this->assertContainsEquals(new ChoiceView('FRA', 'FRA', 'France'), $choices);
$this->assertContainsEquals(new ChoiceView('MYS', 'MYS', 'Malaysia'), $choices);
}
/**
* @requires extension intl
*/
public function testChoiceTranslationLocaleAndAlpha3Option()
{
$choices = $this->factory
->create(static::TESTED_TYPE, null, [
'choice_translation_locale' => 'uk',
'alpha3' => true,
])
->createView()->vars['choices'];
// Don't check objects for identity
$this->assertContainsEquals(new ChoiceView('DEU', 'DEU', 'Німеччина'), $choices);
$this->assertContainsEquals(new ChoiceView('GBR', 'GBR', 'Велика Британія'), $choices);
$this->assertContainsEquals(new ChoiceView('USA', 'USA', 'Сполучені Штати'), $choices);
$this->assertContainsEquals(new ChoiceView('FRA', 'FRA', 'Франція'), $choices);
$this->assertContainsEquals(new ChoiceView('MYS', 'MYS', 'Малайзія'), $choices);
}
public function testUnknownCountryIsNotIncluded() public function testUnknownCountryIsNotIncluded()
{ {
$choices = $this->factory->create(static::TESTED_TYPE, 'country') $choices = $this->factory->create(static::TESTED_TYPE, 'country')

View File

@ -52,6 +52,40 @@ class LanguageTypeTest extends BaseTypeTest
$this->assertContainsEquals(new ChoiceView('my', 'my', 'бірманська'), $choices); $this->assertContainsEquals(new ChoiceView('my', 'my', 'бірманська'), $choices);
} }
public function testAlpha3Option()
{
$choices = $this->factory
->create(static::TESTED_TYPE, null, [
'alpha3' => true,
])
->createView()->vars['choices'];
// Don't check objects for identity
$this->assertContainsEquals(new ChoiceView('eng', 'eng', 'English'), $choices);
$this->assertContainsEquals(new ChoiceView('fra', 'fra', 'French'), $choices);
// Burmese has no three letter language code
$this->assertNotContainsEquals(new ChoiceView('my', 'my', 'Burmese'), $choices);
}
/**
* @requires extension intl
*/
public function testChoiceTranslationLocaleAndAlpha3Option()
{
$choices = $this->factory
->create(static::TESTED_TYPE, null, [
'choice_translation_locale' => 'uk',
'alpha3' => true,
])
->createView()->vars['choices'];
// Don't check objects for identity
$this->assertContainsEquals(new ChoiceView('eng', 'eng', 'англійська'), $choices);
$this->assertContainsEquals(new ChoiceView('fra', 'fra', 'французька'), $choices);
// Burmese has no three letter language code
$this->assertNotContainsEquals(new ChoiceView('my', 'my', 'бірманська'), $choices);
}
public function testMultipleLanguagesIsNotIncluded() public function testMultipleLanguagesIsNotIncluded()
{ {
$choices = $this->factory->create(static::TESTED_TYPE, 'language') $choices = $this->factory->create(static::TESTED_TYPE, 'language')

View File

@ -221,7 +221,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac
]; ];
$proxy = self::getProxy($options['proxy'], $url); $proxy = self::getProxy($options['proxy'], $url);
$noProxy = $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? ''; $noProxy = $options['no_proxy'] ?? $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? '';
$noProxy = $noProxy ? preg_split('/[\s,]+/', $noProxy) : []; $noProxy = $noProxy ? preg_split('/[\s,]+/', $noProxy) : [];
$resolveRedirect = self::createRedirectResolver($options, $host, $proxy, $noProxy, $info, $onProgress); $resolveRedirect = self::createRedirectResolver($options, $host, $proxy, $noProxy, $info, $onProgress);

View File

@ -164,7 +164,7 @@ class HttpClientDataCollectorTest extends TestCase
$this->assertEquals(0, $sut->getRequestCount()); $this->assertEquals(0, $sut->getRequestCount());
} }
private function httpClientThatHasTracedRequests($tracedRequests) private function httpClientThatHasTracedRequests($tracedRequests): TraceableHttpClient
{ {
$httpClient = new TraceableHttpClient(new NativeHttpClient()); $httpClient = new TraceableHttpClient(new NativeHttpClient());

View File

@ -20,7 +20,7 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
*/ */
class HttpExceptionTraitTest extends TestCase class HttpExceptionTraitTest extends TestCase
{ {
public function provideParseError() public function provideParseError(): iterable
{ {
yield ['application/ld+json', '{"hydra:title": "An error occurred", "hydra:description": "Some details"}']; yield ['application/ld+json', '{"hydra:title": "An error occurred", "hydra:description": "Some details"}'];
yield ['application/problem+json', '{"title": "An error occurred", "detail": "Some details"}']; yield ['application/problem+json', '{"title": "An error occurred", "detail": "Some details"}'];

View File

@ -24,7 +24,7 @@ class HttpClientTraitTest extends TestCase
/** /**
* @dataProvider providePrepareRequestUrl * @dataProvider providePrepareRequestUrl
*/ */
public function testPrepareRequestUrl($expected, $url, $query = []) public function testPrepareRequestUrl(string $expected, string $url, array $query = [])
{ {
$defaults = [ $defaults = [
'base_uri' => 'http://example.com?c=c', 'base_uri' => 'http://example.com?c=c',
@ -36,7 +36,7 @@ class HttpClientTraitTest extends TestCase
$this->assertSame($expected, implode('', $url)); $this->assertSame($expected, implode('', $url));
} }
public function providePrepareRequestUrl() public function providePrepareRequestUrl(): iterable
{ {
yield ['http://example.com/', 'http://example.com/']; yield ['http://example.com/', 'http://example.com/'];
yield ['http://example.com/?a=1&b=b', '.']; yield ['http://example.com/?a=1&b=b', '.'];
@ -48,7 +48,7 @@ class HttpClientTraitTest extends TestCase
/** /**
* @dataProvider provideResolveUrl * @dataProvider provideResolveUrl
*/ */
public function testResolveUrl($base, $url, $expected) public function testResolveUrl(string $base, string $url, string $expected)
{ {
$this->assertSame($expected, implode('', self::resolveUrl(self::parseUrl($url), self::parseUrl($base)))); $this->assertSame($expected, implode('', self::resolveUrl(self::parseUrl($url), self::parseUrl($base))));
} }
@ -56,7 +56,7 @@ class HttpClientTraitTest extends TestCase
/** /**
* From https://github.com/guzzle/psr7/blob/master/tests/UriResoverTest.php. * From https://github.com/guzzle/psr7/blob/master/tests/UriResoverTest.php.
*/ */
public function provideResolveUrl() public function provideResolveUrl(): array
{ {
return [ return [
[self::RFC3986_BASE, 'http:h', 'http:h'], [self::RFC3986_BASE, 'http:h', 'http:h'],
@ -123,14 +123,14 @@ class HttpClientTraitTest extends TestCase
/** /**
* @dataProvider provideParseUrl * @dataProvider provideParseUrl
*/ */
public function testParseUrl($expected, $url, $query = []) public function testParseUrl(array $expected, string $url, array $query = [])
{ {
$expected = array_combine(['scheme', 'authority', 'path', 'query', 'fragment'], $expected); $expected = array_combine(['scheme', 'authority', 'path', 'query', 'fragment'], $expected);
$this->assertSame($expected, self::parseUrl($url, $query)); $this->assertSame($expected, self::parseUrl($url, $query));
} }
public function provideParseUrl() public function provideParseUrl(): iterable
{ {
yield [['http:', '//example.com', null, null, null], 'http://Example.coM:80']; yield [['http:', '//example.com', null, null, null], 'http://Example.coM:80'];
yield [['https:', '//xn--dj-kia8a.example.com:8000', '/', null, null], 'https://DÉjà.Example.com:8000/']; yield [['https:', '//xn--dj-kia8a.example.com:8000', '/', null, null], 'https://DÉjà.Example.com:8000/'];

View File

@ -19,7 +19,7 @@ use Symfony\Component\HttpClient\HttpOptions;
*/ */
class HttpOptionsTest extends TestCase class HttpOptionsTest extends TestCase
{ {
public function provideSetAuthBasic() public function provideSetAuthBasic(): iterable
{ {
yield ['user:password', 'user', 'password']; yield ['user:password', 'user', 'password'];
yield ['user:password', 'user:password']; yield ['user:password', 'user:password'];

View File

@ -456,7 +456,7 @@ class NativeSessionStorage implements SessionStorageInterface
foreach ($bags as $bag) { foreach ($bags as $bag) {
$key = $bag->getStorageKey(); $key = $bag->getStorageKey();
$session[$key] = isset($session[$key]) ? $session[$key] : []; $session[$key] = isset($session[$key]) && \is_array($session[$key]) ? $session[$key] : [];
$bag->initialize($session[$key]); $bag->initialize($session[$key]);
} }

View File

@ -147,7 +147,7 @@ class ControllerResolver implements ControllerResolverInterface
return new $class(); return new $class();
} }
private function getControllerError($callable) private function getControllerError($callable): string
{ {
if (\is_string($callable)) { if (\is_string($callable)) {
if (false !== strpos($callable, '::')) { if (false !== strpos($callable, '::')) {
@ -209,7 +209,7 @@ class ControllerResolver implements ControllerResolverInterface
return $message; return $message;
} }
private function getClassMethodsWithoutMagicMethods($classOrObject) private function getClassMethodsWithoutMagicMethods($classOrObject): array
{ {
$methods = get_class_methods($classOrObject); $methods = get_class_methods($classOrObject);

View File

@ -118,7 +118,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return 'logger'; return 'logger';
} }
private function getContainerDeprecationLogs() private function getContainerDeprecationLogs(): array
{ {
if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Deprecations.log')) { if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Deprecations.log')) {
return []; return [];
@ -212,7 +212,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return array_values($sanitizedLogs); return array_values($sanitizedLogs);
} }
private function isSilencedOrDeprecationErrorLog(array $log) private function isSilencedOrDeprecationErrorLog(array $log): bool
{ {
if (!isset($log['context']['exception'])) { if (!isset($log['context']['exception'])) {
return false; return false;
@ -231,7 +231,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
return false; return false;
} }
private function computeErrorsCount(array $containerDeprecationLogs) private function computeErrorsCount(array $containerDeprecationLogs): array
{ {
$silencedLogs = []; $silencedLogs = [];
$count = [ $count = [

View File

@ -89,7 +89,7 @@ class MemoryDataCollector extends DataCollector implements LateDataCollectorInte
return 'memory'; return 'memory';
} }
private function convertToBytes(string $memoryLimit) private function convertToBytes(string $memoryLimit): int
{ {
if ('-1' === $memoryLimit) { if ('-1' === $memoryLimit) {
return -1; return -1;

View File

@ -82,7 +82,7 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
return array_unique($expanded); return array_unique($expanded);
} }
private function getClassesInComposerClassMaps() private function getClassesInComposerClassMaps(): array
{ {
$classes = []; $classes = [];
@ -103,7 +103,7 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
return array_keys($classes); return array_keys($classes);
} }
private function patternsToRegexps(array $patterns) private function patternsToRegexps(array $patterns): array
{ {
$regexps = []; $regexps = [];
@ -125,7 +125,7 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface
return $regexps; return $regexps;
} }
private function matchAnyRegexps(string $class, array $regexps) private function matchAnyRegexps(string $class, array $regexps): bool
{ {
$blacklisted = false !== strpos($class, 'Test'); $blacklisted = false !== strpos($class, 'Test');

View File

@ -16,7 +16,7 @@ namespace Symfony\Component\HttpKernel\Exception;
* *
* @author Kris Wallsmith <kris@symfony.com> * @author Kris Wallsmith <kris@symfony.com>
*/ */
interface HttpExceptionInterface interface HttpExceptionInterface extends \Throwable
{ {
/** /**
* Returns the status code. * Returns the status code.

View File

@ -78,12 +78,12 @@ class UriSigner
return $this->computeHash($this->buildUrl($url, $params)) === $hash; return $this->computeHash($this->buildUrl($url, $params)) === $hash;
} }
private function computeHash(string $uri) private function computeHash(string $uri): string
{ {
return base64_encode(hash_hmac('sha256', $uri, $this->secret, true)); return base64_encode(hash_hmac('sha256', $uri, $this->secret, true));
} }
private function buildUrl(array $url, array $params = []) private function buildUrl(array $url, array $params = []): string
{ {
ksort($params, SORT_STRING); ksort($params, SORT_STRING);
$url['query'] = http_build_query($params, '', '&'); $url['query'] = http_build_query($params, '', '&');

View File

@ -205,7 +205,7 @@ class LanguageDataGenerator extends AbstractDataGenerator
return array_keys($alpha3Codes); return array_keys($alpha3Codes);
} }
private function generateAlpha2ToAlpha3Mapping(ArrayAccessibleResourceBundle $metadataBundle) private function generateAlpha2ToAlpha3Mapping(ArrayAccessibleResourceBundle $metadataBundle): array
{ {
$aliases = iterator_to_array($metadataBundle['alias']['language']); $aliases = iterator_to_array($metadataBundle['alias']['language']);
$alpha2ToAlpha3 = []; $alpha2ToAlpha3 = [];

View File

@ -125,7 +125,7 @@ final class Intl
*/ */
public static function getIcuStubVersion(): string public static function getIcuStubVersion(): string
{ {
return '64.2'; return '65.1';
} }
/** /**

View File

@ -1,9 +1,9 @@
{ {
"Version": "2.1.48.17", "Version": "36",
"Names": { "Names": {
"AED": [ "AED": [
"AED", "AED",
"Verenigde Arabiese Emirate dirham" "Verenigde Arabiese Emirate-dirham"
], ],
"AFN": [ "AFN": [
"AFN", "AFN",
@ -91,11 +91,11 @@
], ],
"BWP": [ "BWP": [
"BWP", "BWP",
"Botswana pula" "Botswana-pula"
], ],
"BYN": [ "BYN": [
"BYN", "BYN",
"Belo-Russiese roebel" "Belarusiese roebel"
], ],
"BYR": [ "BYR": [
"BYR", "BYR",
@ -106,7 +106,7 @@
"Beliziese dollar" "Beliziese dollar"
], ],
"CAD": [ "CAD": [
"CA$", "CAD",
"Kanadese dollar" "Kanadese dollar"
], ],
"CDF": [ "CDF": [
@ -123,11 +123,11 @@
], ],
"CNH": [ "CNH": [
"CNH", "CNH",
"Chinese joean" "Chinese joean (buiteland)"
], ],
"CNY": [ "CNY": [
"CN¥", "CN¥",
"Sjinese joean renminbi" "Chinese joean"
], ],
"COP": [ "COP": [
"COP", "COP",
@ -155,7 +155,7 @@
], ],
"DJF": [ "DJF": [
"DJF", "DJF",
"Djiboeti frank" "Djiboeti-frank"
], ],
"DKK": [ "DKK": [
"DKK", "DKK",
@ -191,7 +191,7 @@
], ],
"FKP": [ "FKP": [
"FKP", "FKP",
"Falkland-eilande pond" "Falkland-eilandse pond"
], ],
"GBP": [ "GBP": [
"£", "£",
@ -235,7 +235,7 @@
], ],
"HKD": [ "HKD": [
"HK$", "HK$",
"Hong Kong dollar" "Hongkongse dollar"
], ],
"HNL": [ "HNL": [
"HNL", "HNL",
@ -323,7 +323,7 @@
], ],
"KYD": [ "KYD": [
"KYD", "KYD",
"Cayman-eilande dollar" "Cayman-eilandse dollar"
], ],
"KZT": [ "KZT": [
"KZT", "KZT",
@ -335,7 +335,7 @@
], ],
"LBP": [ "LBP": [
"LBP", "LBP",
"Lebanese pond" "Libanese pond"
], ],
"LKR": [ "LKR": [
"LKR", "LKR",
@ -399,7 +399,7 @@
], ],
"MUR": [ "MUR": [
"MUR", "MUR",
"Mauritiaanse rupee" "Mauritiaanse roepee"
], ],
"MVR": [ "MVR": [
"MVR", "MVR",
@ -447,7 +447,7 @@
], ],
"NZD": [ "NZD": [
"NZ$", "NZ$",
"Nieu-Seeland dollar" "Nieu-Seelandse dollar"
], ],
"OMR": [ "OMR": [
"OMR", "OMR",
@ -491,7 +491,7 @@
], ],
"RSD": [ "RSD": [
"RSD", "RSD",
"Serbiese dinar" "Serwiese dinar"
], ],
"RUB": [ "RUB": [
"RUB", "RUB",
@ -499,7 +499,7 @@
], ],
"RWF": [ "RWF": [
"RWF", "RWF",
"Rwandiese frank" "Rwandese frank"
], ],
"SAR": [ "SAR": [
"SAR", "SAR",
@ -507,11 +507,11 @@
], ],
"SBD": [ "SBD": [
"SBD", "SBD",
"Salomonseilande dollar" "Salomonseilandse dollar"
], ],
"SCR": [ "SCR": [
"SCR", "SCR",
"Seychellese rupee" "Seychellese roepee"
], ],
"SDG": [ "SDG": [
"SDG", "SDG",
@ -527,11 +527,11 @@
], ],
"SGD": [ "SGD": [
"SGD", "SGD",
"Singapoer dollar" "Singapoer-dollar"
], ],
"SHP": [ "SHP": [
"SHP", "SHP",
"Sint Helena pond" "Sint Helena-pond"
], ],
"SLL": [ "SLL": [
"SLL", "SLL",
@ -555,7 +555,7 @@
], ],
"STN": [ "STN": [
"STN", "STN",
"São Tomé en Príncipe dobra" "São Tomé en Príncipe-dobra"
], ],
"SYP": [ "SYP": [
"SYP", "SYP",
@ -571,7 +571,7 @@
], ],
"TJS": [ "TJS": [
"TJS", "TJS",
"Tadjikse roebel" "Tadjikse somoni"
], ],
"TMT": [ "TMT": [
"TMT", "TMT",
@ -591,11 +591,11 @@
], ],
"TRY": [ "TRY": [
"TRY", "TRY",
"Turkse lier" "Turkse lira"
], ],
"TTD": [ "TTD": [
"TTD", "TTD",
"Trinidad en Tobago dollar" "Trinidad en Tobago-dollar"
], ],
"TWD": [ "TWD": [
"NT$", "NT$",
@ -614,8 +614,8 @@
"Ugandese sjieling" "Ugandese sjieling"
], ],
"USD": [ "USD": [
"US$", "USD",
"Amerikaanse dollar" "VSA-dollar"
], ],
"UYU": [ "UYU": [
"UYU", "UYU",
@ -631,7 +631,7 @@
], ],
"VES": [ "VES": [
"VES", "VES",
"Venezolaanse Bolívar" "Venezolaanse bolívar"
], ],
"VND": [ "VND": [
"₫", "₫",
@ -647,15 +647,15 @@
], ],
"XAF": [ "XAF": [
"FCFA", "FCFA",
"CFA frank BEAC" "Sentraal Afrikaanse CFA-frank"
], ],
"XCD": [ "XCD": [
"EC$", "EC$",
"Oos-Karibbiese dollar" "Oos-Karibiese dollar"
], ],
"XOF": [ "XOF": [
"CFA", "CFA",
"CFA frank BCEAO" "Wes-Afrikaanse CFA-frank"
], ],
"XPF": [ "XPF": [
"CFPF", "CFPF",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.48.22", "Version": "36",
"Names": { "Names": {
"NAD": [ "NAD": [
"$", "$",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.82", "Version": "36",
"Names": { "Names": {
"AED": [ "AED": [
"AED", "AED",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.49.82", "Version": "36",
"Names": { "Names": {
"AED": [ "AED": [
"AED", "AED",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.49.82", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",
@ -105,10 +105,6 @@
"BEL", "BEL",
"فرنك بلجيكي مالي" "فرنك بلجيكي مالي"
], ],
"BGL": [
"BGL",
"BGL"
],
"BGN": [ "BGN": [
"BGN", "BGN",
"ليف بلغاري" "ليف بلغاري"
@ -314,7 +310,7 @@
"فرنك فرنسي" "فرنك فرنسي"
], ],
"GBP": [ "GBP": [
"£", "UK£",
"جنيه إسترليني" "جنيه إسترليني"
], ],
"GEL": [ "GEL": [

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.69", "Version": "36",
"Names": { "Names": {
"DJF": [ "DJF": [
"Fdj", "Fdj",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.69", "Version": "36",
"Names": { "Names": {
"ERN": [ "ERN": [
"Nfk", "Nfk",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.69", "Version": "36",
"Names": { "Names": {
"KMF": [ "KMF": [
"CF", "CF",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.69", "Version": "36",
"Names": { "Names": {
"SDG": [ "SDG": [
"SDG", "SDG",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.69", "Version": "36",
"Names": { "Names": {
"SOS": [ "SOS": [
"S", "S",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.69", "Version": "36",
"Names": { "Names": {
"GBP": [ "GBP": [
"GB£", "GB£",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.48.17", "Version": "36",
"Names": { "Names": {
"AED": [ "AED": [
"AED", "AED",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.49.82", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",
@ -171,7 +171,7 @@
], ],
"BSD": [ "BSD": [
"BSD", "BSD",
"Bahama Dolları" "Baham Dolları"
], ],
"BTN": [ "BTN": [
"BTN", "BTN",
@ -347,7 +347,7 @@
], ],
"GBP": [ "GBP": [
"£", "£",
"Britaniya Funt" "Britaniya Funtu"
], ],
"GEK": [ "GEK": [
"GEK", "GEK",
@ -367,7 +367,7 @@
], ],
"GIP": [ "GIP": [
"GIP", "GIP",
"Gibraltar Funtu" "Cəbəli-Tariq Funtu"
], ],
"GMD": [ "GMD": [
"GMD", "GMD",
@ -491,7 +491,7 @@
], ],
"KGS": [ "KGS": [
"KGS", "KGS",
"Kıızıstan Somu" "Qıızıstan Somu"
], ],
"KHR": [ "KHR": [
"KHR", "KHR",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.82", "Version": "36",
"Names": { "Names": {
"AZN": [ "AZN": [
"₼", "₼",

View File

@ -1,9 +1,9 @@
{ {
"Version": "2.1.49.82", "Version": "36",
"Names": { "Names": {
"AED": [ "AED": [
"AED", "AED",
"дырхем ААЭ" "дырхам ААЭ"
], ],
"AFN": [ "AFN": [
"AFN", "AFN",
@ -47,7 +47,7 @@
], ],
"BBD": [ "BBD": [
"BBD", "BBD",
"барбадоскі долар" "барбадаскі долар"
], ],
"BDT": [ "BDT": [
"BDT", "BDT",
@ -263,7 +263,7 @@
], ],
"IRR": [ "IRR": [
"IRR", "IRR",
"іранскі рыал" "іранскі рыял"
], ],
"ISK": [ "ISK": [
"ISK", "ISK",
@ -291,7 +291,7 @@
], ],
"KHR": [ "KHR": [
"KHR", "KHR",
"камбаджыйскі рыэль" "камбаджыйскі рыель"
], ],
"KMF": [ "KMF": [
"KMF", "KMF",
@ -315,7 +315,7 @@
], ],
"KZT": [ "KZT": [
"KZT", "KZT",
"казахстанскі тэнгэ" "казахстанскі тэнге"
], ],
"LAK": [ "LAK": [
"LAK", "LAK",
@ -371,7 +371,7 @@
], ],
"MRU": [ "MRU": [
"MRU", "MRU",
"маўрытанская ўгія" "маўрытанская угія"
], ],
"MUR": [ "MUR": [
"MUR", "MUR",
@ -403,7 +403,7 @@
], ],
"NGN": [ "NGN": [
"NGN", "NGN",
"нігерыйская найра" "нігерыйская наіра"
], ],
"NIO": [ "NIO": [
"NIO", "NIO",
@ -423,7 +423,7 @@
], ],
"OMR": [ "OMR": [
"OMR", "OMR",
"аманскі рыал" "аманскі рыял"
], ],
"PAB": [ "PAB": [
"PAB", "PAB",
@ -435,7 +435,7 @@
], ],
"PGK": [ "PGK": [
"PGK", "PGK",
"кіна" "кіна Папуа-Новай Гвінеі"
], ],
"PHP": [ "PHP": [
"PHP", "PHP",
@ -455,7 +455,7 @@
], ],
"QAR": [ "QAR": [
"QAR", "QAR",
"катарскі рыал" "катарскі рыял"
], ],
"RON": [ "RON": [
"RON", "RON",
@ -499,11 +499,11 @@
], ],
"SHP": [ "SHP": [
"SHP", "SHP",
"фунт Святой Алены" "фунт в-ва Святой Алены"
], ],
"SLL": [ "SLL": [
"SLL", "SLL",
"леонэ" "сьера-леонскі леонэ"
], ],
"SOS": [ "SOS": [
"SOS", "SOS",
@ -595,7 +595,7 @@
], ],
"VES": [ "VES": [
"VES", "VES",
"венесуальскі балівар" "венесуэльскі балівар"
], ],
"VND": [ "VND": [
"₫", "₫",
@ -603,7 +603,7 @@
], ],
"VUV": [ "VUV": [
"VUV", "VUV",
"вату" "вануацкі вату"
], ],
"WST": [ "WST": [
"WST", "WST",
@ -631,7 +631,7 @@
], ],
"ZAR": [ "ZAR": [
"ZAR", "ZAR",
"паўднёваафрыканскі ранд" "паўднёваафрыканскі рэнд"
], ],
"ZMW": [ "ZMW": [
"ZMW", "ZMW",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.48.42", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",
@ -763,7 +763,7 @@
], ],
"SAR": [ "SAR": [
"SAR", "SAR",
"Саудитскоарабски риал" "саудитски риал"
], ],
"SBD": [ "SBD": [
"SBD", "SBD",
@ -917,6 +917,14 @@
"щ.д.", "щ.д.",
"Щатски долар" "Щатски долар"
], ],
"USN": [
"USN",
"USN"
],
"USS": [
"USS",
"USS"
],
"UYI": [ "UYI": [
"UYI", "UYI",
"Уругвайско песо (индекс на инфлацията)" "Уругвайско песо (индекс на инфлацията)"
@ -979,7 +987,7 @@
], ],
"XPF": [ "XPF": [
"CFPF", "CFPF",
"Френскополинезийски франк" "CFP франк"
], ],
"YDD": [ "YDD": [
"YDD", "YDD",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.82", "Version": "36",
"Names": { "Names": {
"AED": [ "AED": [
"AED", "AED",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.48.36", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.82", "Version": "36",
"Names": { "Names": {
"CNY": [ "CNY": [
"¥", "¥",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.82", "Version": "36",
"Names": { "Names": {
"CNY": [ "CNY": [
"CN¥", "CN¥",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.48.86", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",
@ -45,6 +45,18 @@
"AON", "AON",
"kwanza nevez Angola (19902000)" "kwanza nevez Angola (19902000)"
], ],
"AOR": [
"AOR",
"AOR"
],
"ARA": [
"ARA",
"ARA"
],
"ARL": [
"ARL",
"ARL"
],
"ARM": [ "ARM": [
"ARM", "ARM",
"peso Arcʼhantina (18811970)" "peso Arcʼhantina (18811970)"
@ -105,9 +117,9 @@
"BEF", "BEF",
"lur Belgia" "lur Belgia"
], ],
"BEL": [ "BGL": [
"BEL", "BGL",
"BEL" "BGL"
], ],
"BGM": [ "BGM": [
"BGM", "BGM",
@ -149,10 +161,38 @@
"BOP", "BOP",
"peso Bolivia" "peso Bolivia"
], ],
"BOV": [
"BOV",
"BOV"
],
"BRB": [
"BRB",
"BRB"
],
"BRC": [
"BRC",
"BRC"
],
"BRE": [
"BRE",
"BRE"
],
"BRL": [ "BRL": [
"BRL", "BRL",
"real Brazil" "real Brazil"
], ],
"BRN": [
"BRN",
"BRN"
],
"BRR": [
"BRR",
"BRR"
],
"BRZ": [
"BRZ",
"BRZ"
],
"BSD": [ "BSD": [
"BSD", "BSD",
"dollar Bahamas" "dollar Bahamas"
@ -229,6 +269,10 @@
"COP", "COP",
"peso Kolombia" "peso Kolombia"
], ],
"COU": [
"COU",
"COU"
],
"CRC": [ "CRC": [
"CRC", "CRC",
"colón Costa Rica" "colón Costa Rica"
@ -237,6 +281,10 @@
"CSD", "CSD",
"dinar Serbia (20022006)" "dinar Serbia (20022006)"
], ],
"CSK": [
"CSK",
"CSK"
],
"CUC": [ "CUC": [
"CUC", "CUC",
"peso kemmadus Kuba" "peso kemmadus Kuba"
@ -281,6 +329,14 @@
"DZD", "DZD",
"dinar Aljeria" "dinar Aljeria"
], ],
"ECS": [
"ECS",
"ECS"
],
"ECV": [
"ECV",
"ECV"
],
"EEK": [ "EEK": [
"EEK", "EEK",
"kurunenn Estonia" "kurunenn Estonia"
@ -293,6 +349,10 @@
"ERN", "ERN",
"nakfa Eritrea" "nakfa Eritrea"
], ],
"ESA": [
"ESA",
"ESA"
],
"ESB": [ "ESB": [
"ESB", "ESB",
"peseta gemmadus Spagn" "peseta gemmadus Spagn"
@ -329,10 +389,18 @@
"£ RU", "£ RU",
"lur Breizh-Veur" "lur Breizh-Veur"
], ],
"GEK": [
"GEK",
"GEK"
],
"GEL": [ "GEL": [
"GEL", "GEL",
"lari Jorjia" "lari Jorjia"
], ],
"GHC": [
"GHC",
"GHC"
],
"GHS": [ "GHS": [
"GHS", "GHS",
"cedi Ghana" "cedi Ghana"
@ -365,6 +433,10 @@
"GTQ", "GTQ",
"quetzal Guatemala" "quetzal Guatemala"
], ],
"GWE": [
"GWE",
"GWE"
],
"GWP": [ "GWP": [
"GWP", "GWP",
"peso Ginea-Bissau" "peso Ginea-Bissau"
@ -533,6 +605,10 @@
"LUF", "LUF",
"lur Luksembourg" "lur Luksembourg"
], ],
"LUL": [
"LUL",
"LUL"
],
"LVL": [ "LVL": [
"LVL", "LVL",
"lats Latvia" "lats Latvia"
@ -557,6 +633,10 @@
"MCF", "MCF",
"lur Monaco" "lur Monaco"
], ],
"MDC": [
"MDC",
"MDC"
],
"MDL": [ "MDL": [
"MDL", "MDL",
"leu Moldova" "leu Moldova"
@ -633,6 +713,10 @@
"MXP", "MXP",
"peso arcʼhant Mecʼhiko (18611992)" "peso arcʼhant Mecʼhiko (18611992)"
], ],
"MXV": [
"MXV",
"MXV"
],
"MYR": [ "MYR": [
"MYR", "MYR",
"ringgit Malaysia" "ringgit Malaysia"
@ -689,6 +773,10 @@
"PAB", "PAB",
"balboa Panamá" "balboa Panamá"
], ],
"PEI": [
"PEI",
"PEI"
],
"PEN": [ "PEN": [
"PEN", "PEN",
"sol Perou" "sol Perou"
@ -901,6 +989,10 @@
"UAH", "UAH",
"hryvnia Ukraina" "hryvnia Ukraina"
], ],
"UAK": [
"UAK",
"UAK"
],
"UGS": [ "UGS": [
"UGS", "UGS",
"shilling Ouganda (19661987)" "shilling Ouganda (19661987)"
@ -913,6 +1005,18 @@
"$ SU", "$ SU",
"dollar SU" "dollar SU"
], ],
"USN": [
"USN",
"USN"
],
"USS": [
"USS",
"USS"
],
"UYI": [
"UYI",
"UYI"
],
"UYP": [ "UYP": [
"UYP", "UYP",
"peso Uruguay (19751993)" "peso Uruguay (19751993)"
@ -981,6 +1085,10 @@
"CFPF", "CFPF",
"lur CFP" "lur CFP"
], ],
"XRE": [
"XRE",
"XRE"
],
"YDD": [ "YDD": [
"YDD", "YDD",
"dinar Yemen" "dinar Yemen"
@ -989,6 +1097,10 @@
"YER", "YER",
"rial Yemen" "rial Yemen"
], ],
"YUD": [
"YUD",
"YUD"
],
"YUM": [ "YUM": [
"YUM", "YUM",
"dinar nevez Yougoslavia (19942002)" "dinar nevez Yougoslavia (19942002)"
@ -1001,6 +1113,10 @@
"YUR", "YUR",
"dinar adreizhet Yougoslavia (19921993)" "dinar adreizhet Yougoslavia (19921993)"
], ],
"ZAL": [
"ZAL",
"ZAL"
],
"ZAR": [ "ZAR": [
"ZAR", "ZAR",
"rand Suafrika" "rand Suafrika"
@ -1013,6 +1129,14 @@
"ZMW", "ZMW",
"kwacha Zambia" "kwacha Zambia"
], ],
"ZRN": [
"ZRN",
"ZRN"
],
"ZRZ": [
"ZRZ",
"ZRZ"
],
"ZWD": [ "ZWD": [
"ZWD", "ZWD",
"dollar Zimbabwe (19802008)" "dollar Zimbabwe (19802008)"

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.49.82", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",
@ -1007,7 +1007,7 @@
], ],
"VES": [ "VES": [
"VES", "VES",
"venecuelanski bolivar" "Venecuelanski bolivar"
], ],
"VND": [ "VND": [
"₫", "₫",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.49.82", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",
@ -15,7 +15,7 @@
], ],
"AFN": [ "AFN": [
"AFN", "AFN",
"Авганистански авган" "Афганистански афгани"
], ],
"ALL": [ "ALL": [
"ALL", "ALL",
@ -23,7 +23,7 @@
], ],
"AMD": [ "AMD": [
"AMD", "AMD",
"Јерменски драм" "Арменски драм"
], ],
"ANG": [ "ANG": [
"ANG", "ANG",
@ -31,7 +31,7 @@
], ],
"AOA": [ "AOA": [
"AOA", "AOA",
"анголска кванза" "Анголска кванза"
], ],
"AOK": [ "AOK": [
"AOK", "AOK",
@ -55,7 +55,7 @@
], ],
"ARS": [ "ARS": [
"ARS", "ARS",
"аргентински пезо" "Аргентински пезос"
], ],
"ATS": [ "ATS": [
"ATS", "ATS",
@ -87,7 +87,7 @@
], ],
"BBD": [ "BBD": [
"BBD", "BBD",
"Барбадошки долар" "Барбадоски долар"
], ],
"BDT": [ "BDT": [
"BDT", "BDT",
@ -131,7 +131,7 @@
], ],
"BOB": [ "BOB": [
"BOB", "BOB",
"Боливијски Боливиано" "Боливијски боливиано"
], ],
"BOP": [ "BOP": [
"BOP", "BOP",
@ -155,7 +155,7 @@
], ],
"BRL": [ "BRL": [
"R$", "R$",
"Бразилски Реал" "Бразилски реал"
], ],
"BRN": [ "BRN": [
"BRN", "BRN",
@ -195,7 +195,7 @@
], ],
"BZD": [ "BZD": [
"BZD", "BZD",
"Белизе долар" "Белизеански долар"
], ],
"CAD": [ "CAD": [
"CA$", "CA$",
@ -203,7 +203,7 @@
], ],
"CDF": [ "CDF": [
"CDF", "CDF",
"Конголски франак" "Конгоански франак"
], ],
"CHE": [ "CHE": [
"CHE", "CHE",
@ -223,15 +223,19 @@
], ],
"CLP": [ "CLP": [
"CLP", "CLP",
"Чилеански пезо" "Чилеански пезос"
],
"CNH": [
"CNH",
"Кинески јуан (острвски)"
], ],
"CNY": [ "CNY": [
"CN¥", "CN¥",
"Кинески јуан ренминби" "Кинески јуан"
], ],
"COP": [ "COP": [
"COP", "COP",
"Колумбијски пезо" "Колумбијски пезос"
], ],
"COU": [ "COU": [
"COU", "COU",
@ -251,11 +255,11 @@
], ],
"CUC": [ "CUC": [
"CUC", "CUC",
"кубански конвертибилни песо" "кубански конвертибилни пезос"
], ],
"CUP": [ "CUP": [
"CUP", "CUP",
"Кубански пезо" "Кубански пезос"
], ],
"CVE": [ "CVE": [
"CVE", "CVE",
@ -279,7 +283,7 @@
], ],
"DJF": [ "DJF": [
"DJF", "DJF",
"Џибутански франак" "Џибутски франак"
], ],
"DKK": [ "DKK": [
"DKK", "DKK",
@ -287,7 +291,7 @@
], ],
"DOP": [ "DOP": [
"DOP", "DOP",
"Доминикански пезо" "Доминикански пезос"
], ],
"DZD": [ "DZD": [
"DZD", "DZD",
@ -311,7 +315,7 @@
], ],
"ERN": [ "ERN": [
"ERN", "ERN",
"Еритреанска накфа" "Еритрејска накфа"
], ],
"ESA": [ "ESA": [
"ESA", "ESA",
@ -327,7 +331,7 @@
], ],
"ETB": [ "ETB": [
"ETB", "ETB",
"етиопијски бир" "Етиопијски бир"
], ],
"EUR": [ "EUR": [
"€", "€",
@ -343,7 +347,7 @@
], ],
"FKP": [ "FKP": [
"FKP", "FKP",
"Фокландска острва фунта" "Фолкландска фунта"
], ],
"FRF": [ "FRF": [
"FRF", "FRF",
@ -371,7 +375,7 @@
], ],
"GIP": [ "GIP": [
"GIP", "GIP",
"Гибралташка фунта" "Гибралтаска фунта"
], ],
"GMD": [ "GMD": [
"GMD", "GMD",
@ -407,7 +411,7 @@
], ],
"GYD": [ "GYD": [
"GYD", "GYD",
ујански долар" вајански долар"
], ],
"HKD": [ "HKD": [
"HK$", "HK$",
@ -435,7 +439,7 @@
], ],
"IDR": [ "IDR": [
"IDR", "IDR",
"Индонезијска рупиа" "Индонежанска рупија"
], ],
"IEP": [ "IEP": [
"IEP", "IEP",
@ -455,7 +459,7 @@
], ],
"INR": [ "INR": [
"₹", "₹",
"Индијски Рупи" "Индијска рупија"
], ],
"IQD": [ "IQD": [
"IQD", "IQD",
@ -463,7 +467,7 @@
], ],
"IRR": [ "IRR": [
"IRR", "IRR",
"Ирански риал" "Ирански ријал"
], ],
"ISJ": [ "ISJ": [
"ISJ", "ISJ",
@ -499,7 +503,7 @@
], ],
"KHR": [ "KHR": [
"KHR", "KHR",
"Камбоџијски риел" "Камбоџански ријел"
], ],
"KMF": [ "KMF": [
"KMF", "KMF",
@ -511,7 +515,7 @@
], ],
"KRW": [ "KRW": [
"₩", "₩",
"Јужнокорејски Вон" "Јужнокорејски вон"
], ],
"KWD": [ "KWD": [
"KWD", "KWD",
@ -519,23 +523,23 @@
], ],
"KYD": [ "KYD": [
"KYD", "KYD",
"Кајманска острва долар" "Кајмански долар"
], ],
"KZT": [ "KZT": [
"KZT", "KZT",
"Казахстански тенџ" "Казахстански тенге"
], ],
"LAK": [ "LAK": [
"LAK", "LAK",
"Лаошки кип" "Лаоски кип"
], ],
"LBP": [ "LBP": [
"LBP", "LBP",
ебанска фунта" ибанска фунта"
], ],
"LKR": [ "LKR": [
"LKR", "LKR",
"Шриланкански рупи" "Шриланканска рупија"
], ],
"LRD": [ "LRD": [
"LRD", "LRD",
@ -587,11 +591,11 @@
], ],
"MDL": [ "MDL": [
"MDL", "MDL",
"Молдовски љу" "Молдавски леј"
], ],
"MGA": [ "MGA": [
"MGA", "MGA",
"Малагасијски ариари" "Мадагаскарски аријари"
], ],
"MGF": [ "MGF": [
"MGF", "MGF",
@ -607,7 +611,7 @@
], ],
"MMK": [ "MMK": [
"MMK", "MMK",
"Мјанмашки кјат" "Мијанмарски кјат"
], ],
"MNT": [ "MNT": [
"MNT", "MNT",
@ -615,7 +619,7 @@
], ],
"MOP": [ "MOP": [
"MOP", "MOP",
"Маканишка патака" "Макаоска патака"
], ],
"MRO": [ "MRO": [
"MRO", "MRO",
@ -623,7 +627,7 @@
], ],
"MRU": [ "MRU": [
"MRU", "MRU",
"Мауританијска угвија" "Мауританска огија"
], ],
"MTL": [ "MTL": [
"MTL", "MTL",
@ -635,11 +639,11 @@
], ],
"MUR": [ "MUR": [
"MUR", "MUR",
"Маурицијски рупи" "Маурицијска рупија"
], ],
"MVR": [ "MVR": [
"MVR", "MVR",
"Малдивијска руфија" "Малдивска руфија"
], ],
"MWK": [ "MWK": [
"MWK", "MWK",
@ -647,7 +651,7 @@
], ],
"MXN": [ "MXN": [
"MX$", "MX$",
"Мексички пезо" "Мексички пезос"
], ],
"MXP": [ "MXP": [
"MXP", "MXP",
@ -659,7 +663,7 @@
], ],
"MYR": [ "MYR": [
"MYR", "MYR",
"Малезијски ринггит" "Малезијски рингит"
], ],
"MZE": [ "MZE": [
"MZE", "MZE",
@ -675,7 +679,7 @@
], ],
"NAD": [ "NAD": [
"NAD", "NAD",
"намбијски долар" "Намибијски долар"
], ],
"NGN": [ "NGN": [
"NGN", "NGN",
@ -699,7 +703,7 @@
], ],
"NPR": [ "NPR": [
"NPR", "NPR",
"Непалски рупи" "Непалска рупија"
], ],
"NZD": [ "NZD": [
"NZ$", "NZ$",
@ -727,15 +731,15 @@
], ],
"PGK": [ "PGK": [
"PGK", "PGK",
"Папуа ново-гвинејшка кина" "Папуанска кина"
], ],
"PHP": [ "PHP": [
"PHP", "PHP",
"Филипински пезо" "Филипински пезос"
], ],
"PKR": [ "PKR": [
"PKR", "PKR",
"Пакистански рупи" "Пакистанска рупија"
], ],
"PLN": [ "PLN": [
"зл", "зл",
@ -751,11 +755,11 @@
], ],
"PYG": [ "PYG": [
"PYG", "PYG",
"Парагвајски гуарни" "Парагвајски гварани"
], ],
"QAR": [ "QAR": [
"QAR", "QAR",
"Катаршки ријал" "Катарски ријал"
], ],
"RHD": [ "RHD": [
"RHD", "RHD",
@ -767,7 +771,7 @@
], ],
"RON": [ "RON": [
"RON", "RON",
"Румунски леу" "Румунски леј"
], ],
"RSD": [ "RSD": [
"дин.", "дин.",
@ -783,7 +787,7 @@
], ],
"RWF": [ "RWF": [
"RWF", "RWF",
"Руандански франак" "Руандски франак"
], ],
"SAR": [ "SAR": [
"SAR", "SAR",
@ -791,7 +795,7 @@
], ],
"SBD": [ "SBD": [
"SBD", "SBD",
"Соломонско-острвски долар" "Соломонски долар"
], ],
"SCR": [ "SCR": [
"SCR", "SCR",
@ -819,7 +823,7 @@
], ],
"SHP": [ "SHP": [
"SHP", "SHP",
"Св. јеленска фунта" "Света Јелена фунта"
], ],
"SIT": [ "SIT": [
"SIT", "SIT",
@ -831,20 +835,24 @@
], ],
"SLL": [ "SLL": [
"SLL", "SLL",
"Сијера-леоншки леоне" "Сијералеонски леоне"
], ],
"SOS": [ "SOS": [
"SOS", "SOS",
"СОмалијски шилинг" "Сомалијски шилинг"
], ],
"SRD": [ "SRD": [
"SRD", "SRD",
"СУринамски долар" "Суринамски долар"
], ],
"SRG": [ "SRG": [
"SRG", "SRG",
"Суринамски гилдер" "Суринамски гилдер"
], ],
"SSP": [
"SSP",
"Јужносуданска фунта"
],
"STD": [ "STD": [
"STD", "STD",
"Сао Томе и Принципе добра (19772017)" "Сао Томе и Принципе добра (19772017)"
@ -867,11 +875,11 @@
], ],
"SZL": [ "SZL": [
"SZL", "SZL",
"Свази лилангени" "Свазилендски лилангени"
], ],
"THB": [ "THB": [
"THB", "THB",
"Таи бахт" "Тајски бахт"
], ],
"TJR": [ "TJR": [
"TJR", "TJR",
@ -879,7 +887,7 @@
], ],
"TJS": [ "TJS": [
"TJS", "TJS",
"Таљихистански сомони" "Таџикистански сомони"
], ],
"TMM": [ "TMM": [
"TMM", "TMM",
@ -891,11 +899,11 @@
], ],
"TND": [ "TND": [
"TND", "TND",
"Тунизијски долар" "Туниски динар"
], ],
"TOP": [ "TOP": [
"TOP", "TOP",
"Тонгоншка Панга" "Тонгоанска панга"
], ],
"TPE": [ "TPE": [
"TPE", "TPE",
@ -911,7 +919,7 @@
], ],
"TTD": [ "TTD": [
"TTD", "TTD",
"Тринидад тобагошки долар" "Тринидад-тобагошки долар"
], ],
"TWD": [ "TWD": [
"NT$", "NT$",
@ -959,7 +967,7 @@
], ],
"UYU": [ "UYU": [
"UYU", "UYU",
"Уругвајски пезо" "Уругвајски пезос"
], ],
"UZS": [ "UZS": [
"UZS", "UZS",
@ -1027,7 +1035,7 @@
], ],
"YER": [ "YER": [
"YER", "YER",
"Јеменски риал" "Јеменски ријал"
], ],
"YUD": [ "YUD": [
"YUD", "YUD",
@ -1047,7 +1055,7 @@
], ],
"ZAR": [ "ZAR": [
"ZAR", "ZAR",
"Јужно-афрички ранд" "Јужноафрички ранд"
], ],
"ZMK": [ "ZMK": [
"ZMK", "ZMK",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.48.42", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",
@ -527,7 +527,7 @@
"dinar jordà" "dinar jordà"
], ],
"JPY": [ "JPY": [
"JP¥", "¥",
"ien japonès" "ien japonès"
], ],
"KES": [ "KES": [
@ -928,7 +928,7 @@
], ],
"SYP": [ "SYP": [
"SYP", "SYP",
"lliura síria" "lliura siriana"
], ],
"SZL": [ "SZL": [
"SZL", "SZL",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.69", "Version": "36",
"Names": { "Names": {
"FRF": [ "FRF": [
"F", "F",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.47.82", "Version": "36",
"Names": { "Names": {
"AED": [ "AED": [
"AED", "AED",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.48.44", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.49.82", "Version": "36",
"Names": { "Names": {
"AED": [ "AED": [
"AED", "AED",
@ -759,7 +759,7 @@
], ],
"PHP": [ "PHP": [
"PHP", "PHP",
"Pesor Philipinau" "Peso Philipinas"
], ],
"PKR": [ "PKR": [
"PKR", "PKR",

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.1.49.82", "Version": "36",
"Names": { "Names": {
"ADP": [ "ADP": [
"ADP", "ADP",
@ -403,7 +403,7 @@
], ],
"HKD": [ "HKD": [
"HK$", "HK$",
"Hongkong dollar" "hongkongsk dollar"
], ],
"HNL": [ "HNL": [
"HNL", "HNL",
@ -918,7 +918,7 @@
"ugandisk shilling" "ugandisk shilling"
], ],
"USD": [ "USD": [
"$", "US$",
"amerikansk dollar" "amerikansk dollar"
], ],
"USN": [ "USN": [

Some files were not shown because too many files have changed in this diff Show More