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
---------
* 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.
Before:
@ -939,7 +939,7 @@ VarDumper
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.
Before:

View File

@ -242,6 +242,28 @@ Workflow
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.
Before:

View File

@ -344,6 +344,8 @@ Validator
* 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 `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
-----------------

View File

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

View File

@ -32,6 +32,7 @@ class UnusedTagsPass implements CompilerPassInterface
'controller.service_arguments',
'config_cache.resource_checker',
'data_collector',
'error_renderer.renderer',
'form.type',
'form.type_extension',
'form.type_guesser',
@ -63,6 +64,7 @@ class UnusedTagsPass implements CompilerPassInterface
'twig.loader',
'validator.constraint_validator',
'validator.initializer',
'validator.auto_mapper',
];
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\ExceptionEvent">kernel.exception</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\LeaveEvent">workflow.leave</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\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\EventDispatcher\DependencyInjection\AddEventAliasesPass;
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.
@ -64,5 +71,12 @@ class SecurityBundle extends Bundle
$container->addCompilerPass(new AddSessionDomainConstraintPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new RegisterCsrfTokenClearingLogoutHandlerPass());
$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;
if (null === $item->expiry) {
$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);
continue;
}
@ -84,7 +84,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
unset($metadata[CacheItem::METADATA_TAGS]);
}
// 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;

View File

@ -81,7 +81,7 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
$key = (string) $key;
if (null === $item->expiry) {
$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);
continue;
}
@ -95,7 +95,7 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
if ($metadata) {
// 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()

View File

@ -84,7 +84,7 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
}
if ($metadata) {
// 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->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]);
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->get('foo', function ($item) {
$item->expiresAfter(10);
sleep(1);
usleep(999000);
return 'bar';
});

View File

@ -61,7 +61,7 @@ trait ContractsTrait
static function (CacheItem $item, float $startTime, ?array &$metadata) {
if ($item->expiry > $endTime = microtime(true)) {
$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 {
unset($metadata[CacheItem::METADATA_EXPIRY], $metadata[CacheItem::METADATA_CTIME]);
}

View File

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

View File

@ -308,6 +308,8 @@ HTML
['li div:only-child', ['li-div']],
['div *:only-child', ['li-div', 'foobar-span']],
['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']],
['li:empty', ['third-li', 'fourth-li', 'fifth-li', 'sixth-li']],

View File

@ -100,17 +100,10 @@ class PseudoClassExtension extends AbstractExtension
->addCondition('last() = 1');
}
/**
* @throws ExpressionErrorException
*/
public function translateOnlyOfType(XPathExpr $xpath): XPathExpr
{
$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));
}

View File

@ -24,12 +24,13 @@ class TaggedIteratorArgument extends IteratorArgument
private $needsIndexes = false;
/**
* @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 $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 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 $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 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([]);
@ -41,6 +42,7 @@ class TaggedIteratorArgument extends IteratorArgument
$this->indexAttribute = $indexAttribute;
$this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute ?? ''))).'Name');
$this->needsIndexes = $needsIndexes;
$this->defaultPriorityMethod = $defaultPriorityMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute ?? ''))).'Priority');
}
public function getTag()
@ -62,4 +64,9 @@ class TaggedIteratorArgument extends IteratorArgument
{
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`
* added support for binding iterable and tagged services
* made singly-implemented interfaces detection be scoped by file
* added ability to define a static priority method for tagged service
4.3.0
-----

View File

@ -40,19 +40,43 @@ trait PriorityTaggedServiceTrait
*/
private function findAndSortTaggedServices($tagName, ContainerBuilder $container): array
{
$indexAttribute = $defaultIndexMethod = $needsIndexes = null;
$indexAttribute = $defaultIndexMethod = $needsIndexes = $defaultPriorityMethod = null;
if ($tagName instanceof TaggedIteratorArgument) {
$indexAttribute = $tagName->getIndexAttribute();
$defaultIndexMethod = $tagName->getDefaultIndexMethod();
$needsIndexes = $tagName->needsIndexes();
$defaultPriorityMethod = $tagName->getDefaultPriorityMethod();
$tagName = $tagName->getTag();
}
$services = [];
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) {
$services[$priority][] = new Reference($serviceId);
@ -60,8 +84,10 @@ trait PriorityTaggedServiceTrait
continue;
}
$class = $container->getDefinition($serviceId)->getClass();
$class = $container->getParameterBag()->resolveValue($class) ?: null;
if (!$class) {
$class = $container->getDefinition($serviceId)->getClass();
$class = $container->getParameterBag()->resolveValue($class) ?: null;
}
if (null !== $indexAttribute && isset($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;
}
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));
}

View File

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

View File

@ -244,6 +244,9 @@ class YamlDumper extends Dumper
if (null !== $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);

View File

@ -116,9 +116,9 @@ function iterator(array $values): IteratorArgument
/**
* 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));
}
$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) {
$arguments[$key] = new ServiceLocatorArgument($arguments[$key]);

View File

@ -709,11 +709,11 @@ class YamlFileLoader extends FileLoader
$forLocator = 'tagged_locator' === $value->getTag();
if (\is_array($argument) && isset($argument['tag']) && $argument['tag']) {
if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_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)));
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", "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) {
$argument = new TaggedIteratorArgument($argument, null, null, $forLocator);
} else {

View File

@ -236,6 +236,7 @@
<xsd:attribute name="tag" type="xsd:string" />
<xsd:attribute name="index-by" 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 name="call">

View File

@ -22,6 +22,7 @@ use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarTagClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedForDefaultPriorityClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooTagClass;
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);
}
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()
{
$container = new ContainerBuilder();

View File

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

View File

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

View File

@ -13,4 +13,9 @@ class BarTagClass
{
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';
}
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"/>
</service>
<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 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 id="Psr\Container\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 }
foo_service_tagged_iterator:
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:
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:
class: Bar
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_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));
$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));
}

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_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));
$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));
$taggedIterator = new TaggedIteratorArgument('foo', null, null, true);

View File

@ -9,6 +9,11 @@ CHANGELOG
* The `TraceableEventDispatcherInterface` has been removed.
* 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
-----
@ -18,7 +23,7 @@ CHANGELOG
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 `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\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\DependencyInjection\AddEventAliasesPass;
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@ -67,6 +68,9 @@ class RegisterListenersPassTest extends TestCase
$builder->register('my_event_subscriber', AliasedSubscriber::class)
->addTag('kernel.event_subscriber');
$eventAliasPass = new AddEventAliasesPass([CustomEvent::class => 'custom_event']);
$eventAliasPass->process($builder);
$registerListenersPass = new RegisterListenersPass();
$registerListenersPass->process($builder);
@ -79,6 +83,14 @@ class RegisterListenersPassTest extends TestCase
0,
],
],
[
'addListener',
[
'custom_event',
[new ServiceClosureArgument(new Reference('my_event_subscriber')), 'onCustomEvent'],
0,
],
],
];
$this->assertEquals($expectedCalls, $builder->getDefinition('event_dispatcher')->getMethodCalls());
}
@ -202,8 +214,12 @@ class RegisterListenersPassTest extends TestCase
$container = new ContainerBuilder();
$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('bar', InvokableListenerService::class)->addTag('kernel.event_listener', ['event' => CustomEvent::class, 'method' => 'onEvent']);
$container->register('event_dispatcher');
$eventAliasPass = new AddEventAliasesPass([CustomEvent::class => 'custom_event']);
$eventAliasPass->process($container);
$registerListenersPass = new RegisterListenersPass();
$registerListenersPass->process($container);
@ -217,6 +233,14 @@ class RegisterListenersPassTest extends TestCase
0,
],
],
[
'addListener',
[
'custom_event',
[new ServiceClosureArgument(new Reference('bar')), 'onEvent'],
0,
],
],
];
$this->assertEquals($expectedCalls, $definition->getMethodCalls());
}
@ -249,6 +273,7 @@ final class AliasedSubscriber implements EventSubscriberInterface
{
return [
AliasedEvent::class => 'onAliasedEvent',
CustomEvent::class => 'onCustomEvent',
];
}
}
@ -256,3 +281,7 @@ final class AliasedSubscriber implements EventSubscriberInterface
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.
* marked all dispatched event classes as `@final`
* 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
-----

View File

@ -156,7 +156,7 @@ EOF
return 0;
}
private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, string $shortClassName)
private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, string $shortClassName): string
{
$classes = [];
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]);
}
private function getCoreTypes()
private function getCoreTypes(): array
{
$coreExtension = new CoreExtension();
$loadTypesRefMethod = (new \ReflectionObject($coreExtension))->getMethod('loadTypes');
@ -225,7 +225,7 @@ EOF
return $typesWithDeprecatedOptions;
}
private function findAlternatives(string $name, array $collection)
private function findAlternatives(string $name, array $collection): array
{
$alternatives = [];
foreach ($collection as $item) {

View File

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

View File

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

View File

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

View File

@ -94,7 +94,7 @@ class DateIntervalToStringTransformer implements DataTransformerInterface
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);
}

View File

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

View File

@ -27,16 +27,19 @@ class LanguageType extends AbstractType
$resolver->setDefaults([
'choice_loader' => function (Options $options) {
$choiceTranslationLocale = $options['choice_translation_locale'];
$alpha3 = $options['alpha3'];
return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) {
return array_flip(Languages::getNames($choiceTranslationLocale));
return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $alpha3) {
return array_flip($alpha3 ? Languages::getAlpha3Names($choiceTranslationLocale) : Languages::getNames($choiceTranslationLocale));
});
},
'choice_translation_domain' => false,
'choice_translation_locale' => null,
'alpha3' => false,
]);
$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
*
* @return (string|GroupSequence)[] The validation groups
* @return GroupSequence|(string|GroupSequence)[] The validation groups
*/
private static function resolveValidationGroups($groups, FormInterface $form)
{

View File

@ -288,7 +288,7 @@ class FormRenderer implements FormRendererInterface
/**
* @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()) {
$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);
}
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()
{
$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);
}
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()
{
$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);
$noProxy = $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? '';
$noProxy = $options['no_proxy'] ?? $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? '';
$noProxy = $noProxy ? preg_split('/[\s,]+/', $noProxy) : [];
$resolveRedirect = self::createRedirectResolver($options, $host, $proxy, $noProxy, $info, $onProgress);

View File

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

View File

@ -20,7 +20,7 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
*/
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/problem+json', '{"title": "An error occurred", "detail": "Some details"}'];

View File

@ -24,7 +24,7 @@ class HttpClientTraitTest extends TestCase
/**
* @dataProvider providePrepareRequestUrl
*/
public function testPrepareRequestUrl($expected, $url, $query = [])
public function testPrepareRequestUrl(string $expected, string $url, array $query = [])
{
$defaults = [
'base_uri' => 'http://example.com?c=c',
@ -36,7 +36,7 @@ class HttpClientTraitTest extends TestCase
$this->assertSame($expected, implode('', $url));
}
public function providePrepareRequestUrl()
public function providePrepareRequestUrl(): iterable
{
yield ['http://example.com/', 'http://example.com/'];
yield ['http://example.com/?a=1&b=b', '.'];
@ -48,7 +48,7 @@ class HttpClientTraitTest extends TestCase
/**
* @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))));
}
@ -56,7 +56,7 @@ class HttpClientTraitTest extends TestCase
/**
* From https://github.com/guzzle/psr7/blob/master/tests/UriResoverTest.php.
*/
public function provideResolveUrl()
public function provideResolveUrl(): array
{
return [
[self::RFC3986_BASE, 'http:h', 'http:h'],
@ -123,14 +123,14 @@ class HttpClientTraitTest extends TestCase
/**
* @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);
$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 [['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
{
public function provideSetAuthBasic()
public function provideSetAuthBasic(): iterable
{
yield ['user:password', 'user', 'password'];
yield ['user:password', 'user:password'];

View File

@ -456,7 +456,7 @@ class NativeSessionStorage implements SessionStorageInterface
foreach ($bags as $bag) {
$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]);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -78,12 +78,12 @@ class UriSigner
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));
}
private function buildUrl(array $url, array $params = [])
private function buildUrl(array $url, array $params = []): string
{
ksort($params, SORT_STRING);
$url['query'] = http_build_query($params, '', '&');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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