Merge branch '4.3' into 4.4
* 4.3: (26 commits) Fix Twig 1.x compatibility [Translator] Improve farsi(persian) translations for Form Improve fa translations Spell "triggering" properly Added tests to cover the possibility of having scalars as services. fixed tests on old PHP versions [FrameworkBundle] Inform the user when save_path will be ignored fixed CS [SecurityBundle] Fix profiler dump for non-invokable security listeners fixed CS [Messenger] Doctrine Transport: Support setting auto_setup from DSN [Translator] Load plurals from po files properly [Serializer]: AbstractObjectNormalizer ignores the property types of discriminated classes [EventDispatcher] Add tag kernel.rest on 'debug.event_dispatcher' service [Console] Update to inherit and add licence Add missing test for workflow dump description [Intl] Remove --dev from intl compile autoloader [Messenger] fix publishing headers set on AmqpStamp Remove call to deprecated method [Intl] Init compile tmp volume ...
This commit is contained in:
commit
2e5a8c80c6
@ -76,7 +76,7 @@ class Deprecation
|
||||
// No-op
|
||||
}
|
||||
$line = $trace[$i];
|
||||
$this->trigerringFilePathType = $this->getPathType($file);
|
||||
$this->triggeringFilePathType = $this->getPathType($file);
|
||||
if (isset($line['object']) || isset($line['class'])) {
|
||||
if (isset($line['class']) && 0 === strpos($line['class'], SymfonyTestsListenerFor::class)) {
|
||||
$parsedMsg = unserialize($this->message);
|
||||
@ -88,7 +88,7 @@ class Deprecation
|
||||
// then we need to use the serialized information to determine
|
||||
// if the error has been triggered from vendor code.
|
||||
if (isset($parsedMsg['triggering_file'])) {
|
||||
$this->trigerringFilePathType = $this->getPathType($parsedMsg['triggering_file']);
|
||||
$this->triggeringFilePathType = $this->getPathType($parsedMsg['triggering_file']);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -177,10 +177,10 @@ class Deprecation
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
if (self::PATH_TYPE_SELF === $this->trigerringFilePathType) {
|
||||
if (self::PATH_TYPE_SELF === $this->triggeringFilePathType) {
|
||||
return self::TYPE_SELF;
|
||||
}
|
||||
if (self::PATH_TYPE_UNDETERMINED === $this->trigerringFilePathType) {
|
||||
if (self::PATH_TYPE_UNDETERMINED === $this->triggeringFilePathType) {
|
||||
return self::TYPE_UNDETERMINED;
|
||||
}
|
||||
$erroringFile = $erroringPackage = null;
|
||||
|
@ -522,6 +522,12 @@ class Configuration implements ConfigurationInterface
|
||||
$rootNode
|
||||
->children()
|
||||
->arrayNode('session')
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
return empty($v['handler_id']) && !empty($v['save_path']);
|
||||
})
|
||||
->thenInvalid('Session save path is ignored without a handler service')
|
||||
->end()
|
||||
->info('session configuration')
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
@ -547,7 +553,7 @@ class Configuration implements ConfigurationInterface
|
||||
->scalarNode('gc_divisor')->end()
|
||||
->scalarNode('gc_probability')->defaultValue(1)->end()
|
||||
->scalarNode('gc_maxlifetime')->end()
|
||||
->scalarNode('save_path')->defaultValue('%kernel.cache_dir%/sessions')->end()
|
||||
->scalarNode('save_path')->end()
|
||||
->integerNode('metadata_update_threshold')
|
||||
->defaultValue(0)
|
||||
->info('seconds to wait between 2 session metadata updates')
|
||||
|
@ -900,6 +900,11 @@ class FrameworkExtension extends Extension
|
||||
|
||||
// session handler (the internal callback registered with PHP session management)
|
||||
if (null === $config['handler_id']) {
|
||||
// If the user set a save_path without using a non-default \SessionHandler, it will silently be ignored
|
||||
if (isset($config['save_path'])) {
|
||||
throw new LogicException('Session save path is ignored without a handler service');
|
||||
}
|
||||
|
||||
// Set the handler class to be null
|
||||
$container->getDefinition('session.storage.native')->replaceArgument(1, null);
|
||||
$container->getDefinition('session.storage.php_bridge')->replaceArgument(0, null);
|
||||
@ -907,6 +912,10 @@ class FrameworkExtension extends Extension
|
||||
$container->setAlias('session.handler', $config['handler_id'])->setPrivate(true);
|
||||
}
|
||||
|
||||
if (!isset($config['save_path'])) {
|
||||
$config['save_path'] = ini_get('session.save_path');
|
||||
}
|
||||
|
||||
$container->setParameter('session.save_path', $config['save_path']);
|
||||
|
||||
$container->setParameter('session.metadata.update_threshold', $config['metadata_update_threshold']);
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
<service id="debug.event_dispatcher" class="Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher" decorates="event_dispatcher">
|
||||
<tag name="monolog.logger" channel="event" />
|
||||
<tag name="kernel.reset" method="reset" />
|
||||
<argument type="service" id="debug.event_dispatcher.inner" />
|
||||
<argument type="service" id="debug.stopwatch" />
|
||||
<argument type="service" id="logger" on-invalid="null" />
|
||||
|
@ -301,7 +301,6 @@ class ConfigurationTest extends TestCase
|
||||
'cookie_httponly' => true,
|
||||
'cookie_samesite' => null,
|
||||
'gc_probability' => 1,
|
||||
'save_path' => '%kernel.cache_dir%/sessions',
|
||||
'metadata_update_threshold' => 0,
|
||||
],
|
||||
'request' => [
|
||||
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
$container->loadFromExtension('framework', [
|
||||
'session' => [
|
||||
'handler_id' => null,
|
||||
'save_path' => '/some/path',
|
||||
],
|
||||
]);
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:framework="http://symfony.com/schema/dic/symfony"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
|
||||
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
|
||||
|
||||
<framework:config>
|
||||
<framework:session handler-id="null" save-path="/some/path"/>
|
||||
</framework:config>
|
||||
</container>
|
@ -0,0 +1,4 @@
|
||||
framework:
|
||||
session:
|
||||
handler_id: null
|
||||
save_path: /some/path
|
@ -563,6 +563,14 @@ abstract class FrameworkExtensionTest extends TestCase
|
||||
$this->assertEquals($expected, array_keys($container->getDefinition('session_listener')->getArgument(0)->getValues()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
|
||||
*/
|
||||
public function testNullSessionHandlerWithSavePath()
|
||||
{
|
||||
$this->createContainerFromFile('session_savepath');
|
||||
}
|
||||
|
||||
public function testRequest()
|
||||
{
|
||||
$container = $this->createContainerFromFile('full');
|
||||
|
@ -39,10 +39,6 @@ final class WrappedListener implements ListenerInterface
|
||||
public function __construct($listener)
|
||||
{
|
||||
$this->listener = $listener;
|
||||
|
||||
if (null === self::$hasVarDumper) {
|
||||
self::$hasVarDumper = class_exists(ClassStub::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,8 +72,25 @@ final class WrappedListener implements ListenerInterface
|
||||
|
||||
public function getInfo(): array
|
||||
{
|
||||
if (null === $this->stub) {
|
||||
$this->stub = self::$hasVarDumper ? new ClassStub(\get_class($this->listener)) : \get_class($this->listener);
|
||||
if (null !== $this->stub) {
|
||||
// no-op
|
||||
} elseif (self::$hasVarDumper ?? self::$hasVarDumper = class_exists(ClassStub::class)) {
|
||||
$this->stub = ClassStub::wrapCallable($this->listener);
|
||||
} elseif (\is_array($this->listener)) {
|
||||
$this->stub = (\is_object($this->listener[0]) ? \get_class($this->listener[0]) : $this->listener[0]).'::'.$this->listener[1];
|
||||
} elseif ($this->listener instanceof \Closure) {
|
||||
$r = new \ReflectionFunction($this->listener);
|
||||
if (false !== strpos($r->name, '{closure}')) {
|
||||
$this->stub = 'closure';
|
||||
} elseif ($class = $r->getClosureScopeClass()) {
|
||||
$this->stub = $class->name.'::'.$r->name;
|
||||
} else {
|
||||
$this->stub = $r->name;
|
||||
}
|
||||
} elseif (\is_string($this->listener)) {
|
||||
$this->stub = $this->listener;
|
||||
} else {
|
||||
$this->stub = \get_class($this->listener).'::__invoke';
|
||||
}
|
||||
|
||||
return [
|
||||
|
@ -20,7 +20,6 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator;
|
||||
use Symfony\Component\VarDumper\Caster\ClassStub;
|
||||
|
||||
/**
|
||||
* @group time-sensitive
|
||||
@ -56,9 +55,6 @@ class TraceableFirewallListenerTest extends TestCase
|
||||
|
||||
$listeners = $firewall->getWrappedListeners();
|
||||
$this->assertCount(1, $listeners);
|
||||
$this->assertSame($response, $listeners[0]['response']);
|
||||
$this->assertInstanceOf(ClassStub::class, $listeners[0]['stub']);
|
||||
$this->assertSame(\get_class($listener), (string) $listeners[0]['stub']);
|
||||
$this->assertSame(1, $listenerCalled);
|
||||
$this->assertSame($listener, $listeners[0]['stub']);
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ class ExceptionController
|
||||
$exception = $this->profiler->loadProfile($token)->getCollector('exception')->getException();
|
||||
$template = $this->getTemplate();
|
||||
|
||||
if (!$this->twig->getLoader()->exists($template)) {
|
||||
if (!$this->templateExists($template)) {
|
||||
return new Response($this->errorRenderer->getBody($exception), 200, ['Content-Type' => 'text/html']);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,14 @@
|
||||
<?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\Console\CommandLoader;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
@ -1,5 +1,14 @@
|
||||
<?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\Console\CommandLoader;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
@ -77,11 +77,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets style foreground color.
|
||||
*
|
||||
* @param string|null $color The color name
|
||||
*
|
||||
* @throws InvalidArgumentException When the color name isn't defined
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setForeground($color = null)
|
||||
{
|
||||
@ -99,11 +95,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets style background color.
|
||||
*
|
||||
* @param string|null $color The color name
|
||||
*
|
||||
* @throws InvalidArgumentException When the color name isn't defined
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setBackground($color = null)
|
||||
{
|
||||
@ -126,11 +118,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets some specific style option.
|
||||
*
|
||||
* @param string $option The option name
|
||||
*
|
||||
* @throws InvalidArgumentException When the option name isn't defined
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOption($option)
|
||||
{
|
||||
@ -144,11 +132,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets some specific style option.
|
||||
*
|
||||
* @param string $option The option name
|
||||
*
|
||||
* @throws InvalidArgumentException When the option name isn't defined
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function unsetOption($option)
|
||||
{
|
||||
@ -175,11 +159,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the style to a given text.
|
||||
*
|
||||
* @param string $text The text to style
|
||||
*
|
||||
* @return string
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($text)
|
||||
{
|
||||
|
@ -21,7 +21,7 @@ interface OutputFormatterStyleInterface
|
||||
/**
|
||||
* Sets style foreground color.
|
||||
*
|
||||
* @param string $color The color name
|
||||
* @param string|null $color The color name
|
||||
*/
|
||||
public function setForeground($color = null);
|
||||
|
||||
|
@ -272,7 +272,7 @@ final class ProgressBar
|
||||
*
|
||||
* @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable
|
||||
*/
|
||||
public function iterate(iterable $iterable, ?int $max = null): iterable
|
||||
public function iterate(iterable $iterable, int $max = null): iterable
|
||||
{
|
||||
$this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0));
|
||||
|
||||
|
@ -41,6 +41,7 @@ use Symfony\Component\DependencyInjection\Tests\Compiler\Foo;
|
||||
use Symfony\Component\DependencyInjection\Tests\Compiler\Wither;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\SimilarArgumentsDummy;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
@ -1601,6 +1602,20 @@ class ContainerBuilderTest extends TestCase
|
||||
$this->assertSame(['service_container'], array_keys($container->getDefinitions()));
|
||||
}
|
||||
|
||||
public function testScalarService()
|
||||
{
|
||||
$c = new ContainerBuilder();
|
||||
$c->register('foo', 'string')
|
||||
->setPublic(true)
|
||||
->setFactory([ScalarFactory::class, 'getSomeValue'])
|
||||
;
|
||||
|
||||
$c->compile();
|
||||
|
||||
$this->assertTrue($c->has('foo'));
|
||||
$this->assertSame('some value', $c->get('foo'));
|
||||
}
|
||||
|
||||
public function testWither()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
@ -295,6 +295,16 @@ class ContainerTest extends TestCase
|
||||
$this->assertTrue($sc->has('foo.baz'), '->has() returns true if a get*Method() is defined');
|
||||
}
|
||||
|
||||
public function testScalarService()
|
||||
{
|
||||
$c = new Container();
|
||||
|
||||
$c->set('foo', 'some value');
|
||||
|
||||
$this->assertTrue($c->has('foo'));
|
||||
$this->assertSame('some value', $c->get('foo'));
|
||||
}
|
||||
|
||||
public function testInitialized()
|
||||
{
|
||||
$sc = new ProjectServiceContainer();
|
||||
|
@ -33,6 +33,7 @@ use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Compiler\Foo;
|
||||
use Symfony\Component\DependencyInjection\Tests\Compiler\Wither;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
@ -1226,6 +1227,25 @@ class PhpDumperTest extends TestCase
|
||||
$this->assertSame($foo5, $locator->get('foo5'));
|
||||
}
|
||||
|
||||
public function testScalarService()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('foo', 'string')
|
||||
->setPublic(true)
|
||||
->setFactory([ScalarFactory::class, 'getSomeValue'])
|
||||
;
|
||||
|
||||
$container->compile();
|
||||
|
||||
$dumper = new PhpDumper($container);
|
||||
eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Scalar_Service']));
|
||||
|
||||
$container = new \Symfony_DI_PhpDumper_Test_Scalar_Service();
|
||||
|
||||
$this->assertTrue($container->has('foo'));
|
||||
$this->assertSame('some value', $container->get('foo'));
|
||||
}
|
||||
|
||||
public function testWither()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
|
||||
|
||||
final class ScalarFactory
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getSomeValue()
|
||||
{
|
||||
return 'some value';
|
||||
}
|
||||
}
|
@ -4,15 +4,15 @@
|
||||
<body>
|
||||
<trans-unit id="28">
|
||||
<source>This form should not contain extra fields.</source>
|
||||
<target>این فرم نباید فیلد اضافی داشته باشد.</target>
|
||||
<target>این فرم نباید شامل فیلد اضافه ای باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="29">
|
||||
<source>The uploaded file was too large. Please try to upload a smaller file.</source>
|
||||
<target>فایل بارگذاری شده بسیار بزرگ است. لطفا فایل کوچکتری را بارگزاری کنید.</target>
|
||||
<target>فایل بارگذاری شده بسیار بزرگ می باشد. لطفا فایل کوچکتری را بارگذاری نمایید.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="30">
|
||||
<source>The CSRF token is invalid. Please try to resubmit the form.</source>
|
||||
<target>مقدار CSRF نامعتبر است. لطفا فرم را مجددا ارسال فرمایید..</target>
|
||||
<target>توکن CSRF نامعتبر می باشد. لطفا فرم را مجددا ارسال نمایید.</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -917,8 +917,8 @@ class Request
|
||||
$pos = strrpos($host, ':');
|
||||
}
|
||||
|
||||
if (false !== $pos) {
|
||||
return (int) substr($host, $pos + 1);
|
||||
if (false !== $pos && $port = substr($host, $pos + 1)) {
|
||||
return (int) $port;
|
||||
}
|
||||
|
||||
return 'https' === $this->getScheme() ? 443 : 80;
|
||||
|
@ -2319,6 +2319,18 @@ class RequestTest extends TestCase
|
||||
|
||||
$this->assertSame(443, $request->getPort());
|
||||
}
|
||||
|
||||
public function testTrustedPortDoesNotDefaultToZero()
|
||||
{
|
||||
Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_ALL);
|
||||
|
||||
$request = Request::create('/');
|
||||
$request->server->set('REMOTE_ADDR', '1.1.1.1');
|
||||
$request->headers->set('X-Forwarded-Host', 'test.example.com');
|
||||
$request->headers->set('X-Forwarded-Port', '');
|
||||
|
||||
$this->assertSame(80, $request->getPort());
|
||||
}
|
||||
}
|
||||
|
||||
class RequestContentProxy extends Request
|
||||
|
@ -23,7 +23,7 @@ final class UrlHelper
|
||||
private $requestStack;
|
||||
private $requestContext;
|
||||
|
||||
public function __construct(RequestStack $requestStack, ?RequestContext $requestContext = null)
|
||||
public function __construct(RequestStack $requestStack, RequestContext $requestContext = null)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
$this->requestContext = $requestContext;
|
||||
|
@ -149,7 +149,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte
|
||||
return $logs;
|
||||
}
|
||||
|
||||
private function getContainerCompilerLogs(?string $compilerLogsFilepath = null): array
|
||||
private function getContainerCompilerLogs(string $compilerLogsFilepath = null): array
|
||||
{
|
||||
if (!file_exists($compilerLogsFilepath)) {
|
||||
return [];
|
||||
|
@ -63,7 +63,7 @@ class LocaleAwareListener implements EventSubscriberInterface
|
||||
];
|
||||
}
|
||||
|
||||
private function setLocale(string $locale, ?string $defaultLocale = null): void
|
||||
private function setLocale(string $locale, string $defaultLocale = null): void
|
||||
{
|
||||
foreach ($this->localeAwareServices as $service) {
|
||||
try {
|
||||
|
@ -12,7 +12,7 @@
|
||||
$autoload = __DIR__.'/../../vendor/autoload.php';
|
||||
|
||||
if (!file_exists($autoload)) {
|
||||
bailout('You should run "composer install --dev" in the component before running this script.');
|
||||
bailout('You should run "composer install" in the component before running this script.');
|
||||
}
|
||||
|
||||
require_once $autoload;
|
||||
|
@ -1,8 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ $1 == force ]]; then
|
||||
docker pull jakzal/php-intl
|
||||
fi;
|
||||
[[ $1 == force ]] && docker pull jakzal/php-intl
|
||||
[[ ! -d /tmp/symfony/icu ]] && mkdir -p /tmp/symfony/icu
|
||||
|
||||
docker run \
|
||||
-it --rm --name symfony-intl \
|
||||
|
@ -219,7 +219,7 @@ class MessengerPass implements CompilerPassInterface
|
||||
throw new RuntimeException(sprintf('Invalid handler service "%s": type-hint of argument "$%s" in method "%s::__invoke()" must be a class , "%s" given.', $serviceId, $parameters[0]->getName(), $handlerClass->getName(), $type));
|
||||
}
|
||||
|
||||
return [(string) $parameters[0]->getType()];
|
||||
return [$parameters[0]->getType()->getName()];
|
||||
}
|
||||
|
||||
private function registerReceivers(ContainerBuilder $container, array $busIds)
|
||||
|
@ -418,6 +418,21 @@ class ConnectionTest extends TestCase
|
||||
$connection->channel();
|
||||
}
|
||||
|
||||
public function testAmqpStampHeadersAreUsed()
|
||||
{
|
||||
$factory = new TestAmqpFactory(
|
||||
$this->createMock(\AMQPConnection::class),
|
||||
$this->createMock(\AMQPChannel::class),
|
||||
$this->createMock(\AMQPQueue::class),
|
||||
$amqpExchange = $this->createMock(\AMQPExchange::class)
|
||||
);
|
||||
|
||||
$amqpExchange->expects($this->once())->method('publish')->with('body', null, AMQP_NOPARAM, ['headers' => ['Foo' => 'X', 'Bar' => 'Y']]);
|
||||
|
||||
$connection = Connection::fromDsn('amqp://localhost', [], $factory);
|
||||
$connection->publish('body', ['Foo' => 'X'], 0, new AmqpStamp(null, AMQP_NOPARAM, ['headers' => ['Bar' => 'Y']]));
|
||||
}
|
||||
|
||||
public function testItCanPublishWithTheDefaultRoutingKey()
|
||||
{
|
||||
$factory = new TestAmqpFactory(
|
||||
|
@ -157,61 +157,86 @@ class ConnectionTest extends TestCase
|
||||
/**
|
||||
* @dataProvider buildConfigurationProvider
|
||||
*/
|
||||
public function testBuildConfiguration($dsn, $options, $expectedManager, $expectedTableName, $expectedRedeliverTimeout, $expectedQueue)
|
||||
public function testBuildConfiguration($dsn, $options, $expectedConnection, $expectedTableName, $expectedRedeliverTimeout, $expectedQueue, $expectedAutoSetup)
|
||||
{
|
||||
$config = Connection::buildConfiguration($dsn, $options);
|
||||
$this->assertEquals($expectedManager, $config['connection']);
|
||||
$this->assertEquals($expectedConnection, $config['connection']);
|
||||
$this->assertEquals($expectedTableName, $config['table_name']);
|
||||
$this->assertEquals($expectedRedeliverTimeout, $config['redeliver_timeout']);
|
||||
$this->assertEquals($expectedQueue, $config['queue_name']);
|
||||
$this->assertEquals($expectedAutoSetup, $config['auto_setup']);
|
||||
}
|
||||
|
||||
public function buildConfigurationProvider()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'dsn' => 'doctrine://default',
|
||||
'options' => [],
|
||||
'expectedManager' => 'default',
|
||||
'expectedTableName' => 'messenger_messages',
|
||||
'expectedRedeliverTimeout' => 3600,
|
||||
'expectedQueue' => 'default',
|
||||
yield 'no options' => [
|
||||
'dsn' => 'doctrine://default',
|
||||
'options' => [],
|
||||
'expectedConnection' => 'default',
|
||||
'expectedTableName' => 'messenger_messages',
|
||||
'expectedRedeliverTimeout' => 3600,
|
||||
'expectedQueue' => 'default',
|
||||
'expectedAutoSetup' => true,
|
||||
];
|
||||
|
||||
yield 'test options array' => [
|
||||
'dsn' => 'doctrine://default',
|
||||
'options' => [
|
||||
'table_name' => 'name_from_options',
|
||||
'redeliver_timeout' => 1800,
|
||||
'queue_name' => 'important',
|
||||
'auto_setup' => false,
|
||||
],
|
||||
// test options from options array
|
||||
[
|
||||
'dsn' => 'doctrine://default',
|
||||
'options' => [
|
||||
'table_name' => 'name_from_options',
|
||||
'redeliver_timeout' => 1800,
|
||||
'queue_name' => 'important',
|
||||
],
|
||||
'expectedManager' => 'default',
|
||||
'expectedTableName' => 'name_from_options',
|
||||
'expectedRedeliverTimeout' => 1800,
|
||||
'expectedQueue' => 'important',
|
||||
],
|
||||
// tests options from dsn
|
||||
[
|
||||
'dsn' => 'doctrine://default?table_name=name_from_dsn&redeliver_timeout=1200&queue_name=normal',
|
||||
'options' => [],
|
||||
'expectedManager' => 'default',
|
||||
'expectedTableName' => 'name_from_dsn',
|
||||
'expectedRedeliverTimeout' => 1200,
|
||||
'expectedQueue' => 'normal',
|
||||
],
|
||||
// test options from options array wins over options from dsn
|
||||
[
|
||||
'dsn' => 'doctrine://default?table_name=name_from_dsn&redeliver_timeout=1200&queue_name=normal',
|
||||
'options' => [
|
||||
'table_name' => 'name_from_options',
|
||||
'redeliver_timeout' => 1800,
|
||||
'queue_name' => 'important',
|
||||
],
|
||||
'expectedManager' => 'default',
|
||||
'expectedTableName' => 'name_from_options',
|
||||
'expectedRedeliverTimeout' => 1800,
|
||||
'expectedQueue' => 'important',
|
||||
'expectedConnection' => 'default',
|
||||
'expectedTableName' => 'name_from_options',
|
||||
'expectedRedeliverTimeout' => 1800,
|
||||
'expectedQueue' => 'important',
|
||||
'expectedAutoSetup' => false,
|
||||
];
|
||||
|
||||
yield 'options from dsn' => [
|
||||
'dsn' => 'doctrine://default?table_name=name_from_dsn&redeliver_timeout=1200&queue_name=normal&auto_setup=false',
|
||||
'options' => [],
|
||||
'expectedConnection' => 'default',
|
||||
'expectedTableName' => 'name_from_dsn',
|
||||
'expectedRedeliverTimeout' => 1200,
|
||||
'expectedQueue' => 'normal',
|
||||
'expectedAutoSetup' => false,
|
||||
];
|
||||
|
||||
yield 'options from options array wins over options from dsn' => [
|
||||
'dsn' => 'doctrine://default?table_name=name_from_dsn&redeliver_timeout=1200&queue_name=normal&auto_setup=true',
|
||||
'options' => [
|
||||
'table_name' => 'name_from_options',
|
||||
'redeliver_timeout' => 1800,
|
||||
'queue_name' => 'important',
|
||||
'auto_setup' => false,
|
||||
],
|
||||
'expectedConnection' => 'default',
|
||||
'expectedTableName' => 'name_from_options',
|
||||
'expectedRedeliverTimeout' => 1800,
|
||||
'expectedQueue' => 'important',
|
||||
'expectedAutoSetup' => false,
|
||||
];
|
||||
|
||||
yield 'options from dsn with falsey boolean' => [
|
||||
'dsn' => 'doctrine://default?auto_setup=0',
|
||||
'options' => [],
|
||||
'expectedConnection' => 'default',
|
||||
'expectedTableName' => 'messenger_messages',
|
||||
'expectedRedeliverTimeout' => 3600,
|
||||
'expectedQueue' => 'default',
|
||||
'expectedAutoSetup' => false,
|
||||
];
|
||||
|
||||
yield 'options from dsn with thruthy boolean' => [
|
||||
'dsn' => 'doctrine://default?auto_setup=1',
|
||||
'options' => [],
|
||||
'expectedConnection' => 'default',
|
||||
'expectedTableName' => 'messenger_messages',
|
||||
'expectedRedeliverTimeout' => 3600,
|
||||
'expectedQueue' => 'default',
|
||||
'expectedAutoSetup' => true,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -11,13 +11,13 @@
|
||||
|
||||
namespace Symfony\Component\Messenger\Transport\AmqpExt;
|
||||
|
||||
use Symfony\Component\Messenger\Stamp\StampInterface;
|
||||
use Symfony\Component\Messenger\Stamp\NonSendableStampInterface;
|
||||
|
||||
/**
|
||||
* @author Guillaume Gammelin <ggammelin@gmail.com>
|
||||
* @author Samuel Roze <samuel.roze@gmail.com>
|
||||
*/
|
||||
final class AmqpStamp implements StampInterface
|
||||
final class AmqpStamp implements NonSendableStampInterface
|
||||
{
|
||||
private $routingKey;
|
||||
private $flags;
|
||||
|
@ -189,9 +189,7 @@ class Connection
|
||||
$this->exchange(),
|
||||
$body,
|
||||
$this->getRoutingKeyForMessage($amqpStamp),
|
||||
[
|
||||
'headers' => $headers,
|
||||
],
|
||||
$headers,
|
||||
$amqpStamp
|
||||
);
|
||||
}
|
||||
@ -221,20 +219,21 @@ class Connection
|
||||
$this->getDelayExchange(),
|
||||
$body,
|
||||
$this->getRoutingKeyForDelay($delay, $routingKey),
|
||||
[
|
||||
'headers' => $headers,
|
||||
],
|
||||
$headers,
|
||||
$amqpStamp
|
||||
);
|
||||
}
|
||||
|
||||
private function publishOnExchange(\AMQPExchange $exchange, string $body, string $routingKey = null, array $attributes = [], AmqpStamp $amqpStamp = null)
|
||||
private function publishOnExchange(\AMQPExchange $exchange, string $body, string $routingKey = null, array $headers = [], AmqpStamp $amqpStamp = null)
|
||||
{
|
||||
$attributes = $amqpStamp ? $amqpStamp->getAttributes() : [];
|
||||
$attributes['headers'] = array_merge($headers, $attributes['headers'] ?? []);
|
||||
|
||||
$exchange->publish(
|
||||
$body,
|
||||
$routingKey,
|
||||
$amqpStamp ? $amqpStamp->getFlags() : AMQP_NOPARAM,
|
||||
array_merge($amqpStamp ? $amqpStamp->getAttributes() : [], $attributes)
|
||||
$attributes
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -74,22 +74,19 @@ class Connection
|
||||
parse_str($components['query'], $query);
|
||||
}
|
||||
|
||||
$configuration = [
|
||||
'connection' => $components['host'],
|
||||
'table_name' => $options['table_name'] ?? ($query['table_name'] ?? self::DEFAULT_OPTIONS['table_name']),
|
||||
'queue_name' => $options['queue_name'] ?? ($query['queue_name'] ?? self::DEFAULT_OPTIONS['queue_name']),
|
||||
'redeliver_timeout' => $options['redeliver_timeout'] ?? ($query['redeliver_timeout'] ?? self::DEFAULT_OPTIONS['redeliver_timeout']),
|
||||
'auto_setup' => $options['auto_setup'] ?? ($query['auto_setup'] ?? self::DEFAULT_OPTIONS['auto_setup']),
|
||||
];
|
||||
$configuration = ['connection' => $components['host']];
|
||||
$configuration += $options + $query + self::DEFAULT_OPTIONS;
|
||||
|
||||
$configuration['auto_setup'] = filter_var($configuration['auto_setup'], FILTER_VALIDATE_BOOLEAN);
|
||||
|
||||
// check for extra keys in options
|
||||
$optionsExtraKeys = array_diff(array_keys($options), array_keys($configuration));
|
||||
$optionsExtraKeys = array_diff(array_keys($options), array_keys(self::DEFAULT_OPTIONS));
|
||||
if (0 < \count($optionsExtraKeys)) {
|
||||
throw new InvalidArgumentException(sprintf('Unknown option found : [%s]. Allowed options are [%s]', implode(', ', $optionsExtraKeys), implode(', ', self::DEFAULT_OPTIONS)));
|
||||
}
|
||||
|
||||
// check for extra keys in options
|
||||
$queryExtraKeys = array_diff(array_keys($query), array_keys($configuration));
|
||||
$queryExtraKeys = array_diff(array_keys($query), array_keys(self::DEFAULT_OPTIONS));
|
||||
if (0 < \count($queryExtraKeys)) {
|
||||
throw new InvalidArgumentException(sprintf('Unknown option found in DSN: [%s]. Allowed options are [%s]', implode(', ', $queryExtraKeys), implode(', ', self::DEFAULT_OPTIONS)));
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class AuthenticationTrustResolver implements AuthenticationTrustResolverInterfac
|
||||
private $anonymousClass;
|
||||
private $rememberMeClass;
|
||||
|
||||
public function __construct(?string $anonymousClass = null, ?string $rememberMeClass = null)
|
||||
public function __construct(string $anonymousClass = null, string $rememberMeClass = null)
|
||||
{
|
||||
$this->anonymousClass = $anonymousClass;
|
||||
$this->rememberMeClass = $rememberMeClass;
|
||||
|
@ -21,7 +21,7 @@ final class ObjectPropertyListExtractor implements ObjectPropertyListExtractorIn
|
||||
private $propertyListExtractor;
|
||||
private $objectClassResolver;
|
||||
|
||||
public function __construct(PropertyListExtractorInterface $propertyListExtractor, ?callable $objectClassResolver = null)
|
||||
public function __construct(PropertyListExtractorInterface $propertyListExtractor, callable $objectClassResolver = null)
|
||||
{
|
||||
$this->propertyListExtractor = $propertyListExtractor;
|
||||
$this->objectClassResolver = $objectClassResolver;
|
||||
|
@ -330,13 +330,14 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
|
||||
|
||||
$reflectionClass = new \ReflectionClass($class);
|
||||
$object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes, $format);
|
||||
$resolvedClass = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object);
|
||||
|
||||
foreach ($normalizedData as $attribute => $value) {
|
||||
if ($this->nameConverter) {
|
||||
$attribute = $this->nameConverter->denormalize($attribute, $class, $format, $context);
|
||||
$attribute = $this->nameConverter->denormalize($attribute, $resolvedClass, $format, $context);
|
||||
}
|
||||
|
||||
if ((false !== $allowedAttributes && !\in_array($attribute, $allowedAttributes)) || !$this->isAllowedAttribute($class, $attribute, $format, $context)) {
|
||||
if ((false !== $allowedAttributes && !\in_array($attribute, $allowedAttributes)) || !$this->isAllowedAttribute($resolvedClass, $attribute, $format, $context)) {
|
||||
if (!($context[self::ALLOW_EXTRA_ATTRIBUTES] ?? $this->defaultContext[self::ALLOW_EXTRA_ATTRIBUTES])) {
|
||||
$extraAttributes[] = $attribute;
|
||||
}
|
||||
@ -351,7 +352,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
|
||||
}
|
||||
}
|
||||
|
||||
$value = $this->validateAndDenormalize($class, $attribute, $value, $format, $context);
|
||||
$value = $this->validateAndDenormalize($resolvedClass, $attribute, $value, $format, $context);
|
||||
try {
|
||||
$this->setAttributeValue($object, $attribute, $value, $format, $context);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
|
@ -15,10 +15,23 @@ class AbstractDummyFirstChild extends AbstractDummy
|
||||
{
|
||||
public $bar;
|
||||
|
||||
/** @var DummyFirstChildQuux|null */
|
||||
public $quux;
|
||||
|
||||
public function __construct($foo = null, $bar = null)
|
||||
{
|
||||
parent::__construct($foo);
|
||||
|
||||
$this->bar = $bar;
|
||||
}
|
||||
|
||||
public function getQuux(): ?DummyFirstChildQuux
|
||||
{
|
||||
return $this->quux;
|
||||
}
|
||||
|
||||
public function setQuux(DummyFirstChildQuux $quux): void
|
||||
{
|
||||
$this->quux = $quux;
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,23 @@ class AbstractDummySecondChild extends AbstractDummy
|
||||
{
|
||||
public $baz;
|
||||
|
||||
/** @var DummySecondChildQuux|null */
|
||||
public $quux;
|
||||
|
||||
public function __construct($foo = null, $baz = null)
|
||||
{
|
||||
parent::__construct($foo);
|
||||
|
||||
$this->baz = $baz;
|
||||
}
|
||||
|
||||
public function getQuux(): ?DummySecondChildQuux
|
||||
{
|
||||
return $this->quux;
|
||||
}
|
||||
|
||||
public function setQuux(DummySecondChildQuux $quux): void
|
||||
{
|
||||
$this->quux = $quux;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
<?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\Serializer\Tests\Fixtures;
|
||||
|
||||
class DummyFirstChildQuux
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $value;
|
||||
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?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\Serializer\Tests\Fixtures;
|
||||
|
||||
class DummySecondChildQuux
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $value;
|
||||
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
@ -16,13 +16,22 @@ use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
|
||||
use Symfony\Component\PropertyInfo\Type;
|
||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
|
||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
|
||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
|
||||
use Symfony\Component\Serializer\Mapping\ClassMetadata;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Serializer\SerializerAwareInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummy;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyFirstChild;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\DummySecondChildQuux;
|
||||
|
||||
class AbstractObjectNormalizerTest extends TestCase
|
||||
{
|
||||
@ -147,6 +156,39 @@ class AbstractObjectNormalizerTest extends TestCase
|
||||
return $denormalizer;
|
||||
}
|
||||
|
||||
public function testDenormalizeWithDiscriminatorMapUsesCorrectClassname()
|
||||
{
|
||||
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
||||
$loaderMock = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock();
|
||||
$loaderMock->method('hasMetadataFor')->willReturnMap([
|
||||
[
|
||||
AbstractDummy::class,
|
||||
true,
|
||||
],
|
||||
]);
|
||||
|
||||
$loaderMock->method('getMetadataFor')->willReturnMap([
|
||||
[
|
||||
AbstractDummy::class,
|
||||
new ClassMetadata(
|
||||
AbstractDummy::class,
|
||||
new ClassDiscriminatorMapping('type', [
|
||||
'first' => AbstractDummyFirstChild::class,
|
||||
'second' => AbstractDummySecondChild::class,
|
||||
])
|
||||
),
|
||||
],
|
||||
]);
|
||||
|
||||
$discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock);
|
||||
$normalizer = new AbstractObjectNormalizerDummy($factory, null, new PhpDocExtractor(), $discriminatorResolver);
|
||||
$serializer = new Serializer([$normalizer]);
|
||||
$normalizer->setSerializer($serializer);
|
||||
$normalizedData = $normalizer->denormalize(['foo' => 'foo', 'baz' => 'baz', 'quux' => ['value' => 'quux'], 'type' => 'second'], AbstractDummy::class);
|
||||
|
||||
$this->assertInstanceOf(DummySecondChildQuux::class, $normalizedData->quux);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that additional attributes throw an exception if no metadata factory is specified.
|
||||
*
|
||||
@ -180,7 +222,7 @@ class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
|
||||
|
||||
protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = [])
|
||||
{
|
||||
return \in_array($attribute, ['foo', 'baz']);
|
||||
return \in_array($attribute, ['foo', 'baz', 'quux', 'value']);
|
||||
}
|
||||
|
||||
public function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, string $format = null)
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Serializer\Tests;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
|
||||
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
|
||||
@ -34,6 +35,7 @@ use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummy;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyFirstChild;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\DummyFirstChildQuux;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo;
|
||||
@ -382,6 +384,7 @@ class SerializerTest extends TestCase
|
||||
public function testDeserializeAndSerializeAbstractObjectsWithTheClassMetadataDiscriminatorResolver()
|
||||
{
|
||||
$example = new AbstractDummyFirstChild('foo-value', 'bar-value');
|
||||
$example->setQuux(new DummyFirstChildQuux('quux'));
|
||||
|
||||
$loaderMock = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock();
|
||||
$loaderMock->method('hasMetadataFor')->willReturnMap([
|
||||
@ -405,9 +408,9 @@ class SerializerTest extends TestCase
|
||||
]);
|
||||
|
||||
$discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock);
|
||||
$serializer = new Serializer([new ObjectNormalizer(null, null, null, null, $discriminatorResolver)], ['json' => new JsonEncoder()]);
|
||||
$serializer = new Serializer([new ObjectNormalizer(null, null, null, new PhpDocExtractor(), $discriminatorResolver)], ['json' => new JsonEncoder()]);
|
||||
|
||||
$jsonData = '{"type":"first","bar":"bar-value","foo":"foo-value"}';
|
||||
$jsonData = '{"type":"first","quux":{"value":"quux"},"bar":"bar-value","foo":"foo-value"}';
|
||||
|
||||
$deserialized = $serializer->deserialize($jsonData, AbstractDummy::class, 'json');
|
||||
$this->assertEquals($example, $deserialized);
|
||||
|
@ -111,17 +111,12 @@ class MoFileLoader extends FileLoader
|
||||
$ids = ['singular' => $singularId, 'plural' => $pluralId];
|
||||
$item = compact('ids', 'translated');
|
||||
|
||||
if (\is_array($item['translated'])) {
|
||||
$messages[$item['ids']['singular']] = stripcslashes($item['translated'][0]);
|
||||
if (!empty($item['ids']['singular'])) {
|
||||
$id = $item['ids']['singular'];
|
||||
if (isset($item['ids']['plural'])) {
|
||||
$plurals = [];
|
||||
foreach ($item['translated'] as $plural => $translated) {
|
||||
$plurals[] = sprintf('{%d} %s', $plural, $translated);
|
||||
}
|
||||
$messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
|
||||
$id .= '|'.$item['ids']['plural'];
|
||||
}
|
||||
} elseif (!empty($item['ids']['singular'])) {
|
||||
$messages[$item['ids']['singular']] = stripcslashes($item['translated']);
|
||||
$messages[$id] = stripcslashes(implode('|', (array) $item['translated']));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,23 +126,24 @@ class PoFileLoader extends FileLoader
|
||||
*/
|
||||
private function addMessage(array &$messages, array $item)
|
||||
{
|
||||
if (\is_array($item['translated'])) {
|
||||
$messages[stripcslashes($item['ids']['singular'])] = stripcslashes($item['translated'][0]);
|
||||
if (!empty($item['ids']['singular'])) {
|
||||
$id = stripcslashes($item['ids']['singular']);
|
||||
if (isset($item['ids']['plural'])) {
|
||||
$plurals = $item['translated'];
|
||||
// PO are by definition indexed so sort by index.
|
||||
ksort($plurals);
|
||||
// Make sure every index is filled.
|
||||
end($plurals);
|
||||
$count = key($plurals);
|
||||
// Fill missing spots with '-'.
|
||||
$empties = array_fill(0, $count + 1, '-');
|
||||
$plurals += $empties;
|
||||
ksort($plurals);
|
||||
$messages[stripcslashes($item['ids']['plural'])] = stripcslashes(implode('|', $plurals));
|
||||
$id .= '|'.stripcslashes($item['ids']['plural']);
|
||||
}
|
||||
} elseif (!empty($item['ids']['singular'])) {
|
||||
$messages[stripcslashes($item['ids']['singular'])] = stripcslashes($item['translated']);
|
||||
|
||||
$translated = (array) $item['translated'];
|
||||
// PO are by definition indexed so sort by index.
|
||||
ksort($translated);
|
||||
// Make sure every index is filled.
|
||||
end($translated);
|
||||
$count = key($translated);
|
||||
// Fill missing spots with '-'.
|
||||
$empties = array_fill(0, $count + 1, '-');
|
||||
$translated += $empties;
|
||||
ksort($translated);
|
||||
|
||||
$messages[$id] = stripcslashes(implode('|', $translated));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,10 @@ class MoFileLoaderTest extends TestCase
|
||||
$resource = __DIR__.'/../fixtures/plurals.mo';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals(['foo' => 'bar', 'foos' => '{0} bar|{1} bars'], $catalogue->all('domain1'));
|
||||
$this->assertEquals([
|
||||
'foo|foos' => 'bar|bars',
|
||||
'{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars',
|
||||
], $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
$this->assertEquals([new FileResource($resource)], $catalogue->getResources());
|
||||
}
|
||||
|
@ -35,8 +35,7 @@ class PoFileLoaderTest extends TestCase
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals([
|
||||
'foo' => 'bar',
|
||||
'foos' => 'bar|bars',
|
||||
'foo|foos' => 'bar|bars',
|
||||
'{0} no foos|one foo|%count% foos' => '{0} no bars|one bar|%count% bars',
|
||||
], $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
@ -93,10 +92,8 @@ class PoFileLoaderTest extends TestCase
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$messages = $catalogue->all('domain1');
|
||||
$this->assertArrayHasKey('escaped "foo"', $messages);
|
||||
$this->assertArrayHasKey('escaped "foos"', $messages);
|
||||
$this->assertEquals('escaped "bar"', $messages['escaped "foo"']);
|
||||
$this->assertEquals('escaped "bar"|escaped "bars"', $messages['escaped "foos"']);
|
||||
$this->assertArrayHasKey('escaped "foo"|escaped "foos"', $messages);
|
||||
$this->assertEquals('escaped "bar"|escaped "bars"', $messages['escaped "foo"|escaped "foos"']);
|
||||
}
|
||||
|
||||
public function testSkipFuzzyTranslations()
|
||||
@ -110,4 +107,16 @@ class PoFileLoaderTest extends TestCase
|
||||
$this->assertArrayNotHasKey('foo2', $messages);
|
||||
$this->assertArrayHasKey('foo3', $messages);
|
||||
}
|
||||
|
||||
public function testMissingPlurals()
|
||||
{
|
||||
$loader = new PoFileLoader();
|
||||
$resource = __DIR__.'/../fixtures/missing-plurals.po';
|
||||
$catalogue = $loader->load($resource, 'en', 'domain1');
|
||||
|
||||
$this->assertEquals([
|
||||
'foo|foos' => '-|bar|-|bars',
|
||||
], $catalogue->all('domain1'));
|
||||
$this->assertEquals('en', $catalogue->getLocale());
|
||||
}
|
||||
}
|
||||
|
4
src/Symfony/Component/Translation/Tests/fixtures/missing-plurals.po
vendored
Normal file
4
src/Symfony/Component/Translation/Tests/fixtures/missing-plurals.po
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
msgid "foo"
|
||||
msgid_plural "foos"
|
||||
msgstr[3] "bars"
|
||||
msgstr[1] "bar"
|
Binary file not shown.
@ -16,19 +16,19 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="4">
|
||||
<source>This value should be blank.</source>
|
||||
<target>این فیلد باید خالی باشد.</target>
|
||||
<target>این مقدار باید خالی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="5">
|
||||
<source>The value you selected is not a valid choice.</source>
|
||||
<target>گزینه انتخابی معتبر نیست.</target>
|
||||
<target>مقدار انتخاب شده شامل گزینه های معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="6">
|
||||
<source>You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.</source>
|
||||
<target>باید حداقل {{ limit }} گزینه انتخاب کنید.|باید حداقل {{ limit }} گزینه انتخاب کنید.</target>
|
||||
<target>باید حداقل {{ limit }} گزینه انتخاب نمایید.|باید حداقل {{ limit }} گزینه انتخاب نمایید.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="7">
|
||||
<source>You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.</source>
|
||||
<target>حداکثر {{ limit }} گزینه می توانید انتخاب کنید.|حداکثر {{ limit }} گزینه می توانید انتخاب کنید.</target>
|
||||
<target>حداکثر {{ limit }} گزینه می توانید انتخاب نمایید.|حداکثر {{ limit }} گزینه می توانید انتخاب نمایید.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="8">
|
||||
<source>One or more of the given values is invalid.</source>
|
||||
@ -44,87 +44,87 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="11">
|
||||
<source>This value is not a valid date.</source>
|
||||
<target>این مقدار یک تاریخ معتبر نیست.</target>
|
||||
<target>این مقدار یک تاریخ معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="12">
|
||||
<source>This value is not a valid datetime.</source>
|
||||
<target>این مقدار یک تاریخ و زمان معتبر نیست.</target>
|
||||
<target>این مقدار یک تاریخ و زمان معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="13">
|
||||
<source>This value is not a valid email address.</source>
|
||||
<target>این یک رایانامه معتبر نیست.</target>
|
||||
<target>این یک رایانامه معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="14">
|
||||
<source>The file could not be found.</source>
|
||||
<target>فایل پیدا نشد.</target>
|
||||
<target>فایل یافت نشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="15">
|
||||
<source>The file is not readable.</source>
|
||||
<target>فایل قابلیت خواندن ندارد.</target>
|
||||
<target>فایل قابلیت خوانده شدن ندارد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="16">
|
||||
<source>The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.</source>
|
||||
<target>فایل بیش از اندازه بزرگ است({{ size }} {{ suffix }}). حداکثر اندازه مجاز برابر {{ limit }} {{ suffix }} است.</target>
|
||||
<target>فایل بیش از اندازه بزرگ است({{ size }} {{ suffix }}). حداکثر اندازه مجاز برابر با {{ limit }} {{ suffix }} می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="17">
|
||||
<source>The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}.</source>
|
||||
<target>این نوع فایل مجاز نیست({{ type }}). نوع های مجاز {{ types }} هستند.</target>
|
||||
<target>این نوع فایل مجاز نمی باشد({{ type }}). نوع های مجاز شامل {{ types }} می باشند.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="18">
|
||||
<source>This value should be {{ limit }} or less.</source>
|
||||
<target>این مقدار باید کوچکتر یا مساوی {{ limit }} باشد.</target>
|
||||
<target>این مقدار باید کوچکتر و یا مساوی {{ limit }} باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="19">
|
||||
<source>This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.</source>
|
||||
<target>بسیار طولانی است.حداکثر تعداد حروف مجاز برابر {{ limit }} است.|بسیار طولانی است.حداکثر تعداد حروف مجاز برابر {{ limit }} است.</target>
|
||||
<target>بسیار طولانی است.حداکثر تعداد حروف مجاز برابر {{ limit }} می باشد.|بسیار طولانی است.حداکثر تعداد حروف مجاز برابر {{ limit }} می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="20">
|
||||
<source>This value should be {{ limit }} or more.</source>
|
||||
<target>این مقدار باید برابر و یا بیشتر از {{ limit }} باشد.</target>
|
||||
<target>این مقدار باید بزرگتر و یا مساوی {{ limit }} باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="21">
|
||||
<source>This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.</source>
|
||||
<target>بسیار کوتاه است.تعداد حروف باید حداقل {{ limit }} باشد.|بسیار کوتاه است.تعداد حروف باید حداقل {{ limit }} باشد.</target>
|
||||
<target>مقدار وارد شده بسیار کوتاه است.تعداد حروف وارد شده، باید حداقل شامل {{ limit }} کاراکتر باشد.|مقدار وارد شده بسیار کوتاه است.تعداد حروف وارد شده، باید حداقل شامل {{ limit }} کاراکتر باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="22">
|
||||
<source>This value should not be blank.</source>
|
||||
<target>این مقدار نباید تهی باشد.</target>
|
||||
<target>این مقدار نباید خالی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="23">
|
||||
<source>This value should not be null.</source>
|
||||
<target>باید مقداری داشته باشد..</target>
|
||||
<target>این مقدار باید شامل چیزی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="24">
|
||||
<source>This value should be null.</source>
|
||||
<target>نباید مقداری داشته باشد.</target>
|
||||
<target>این مقدار باید شامل چیزی نباشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="25">
|
||||
<source>This value is not valid.</source>
|
||||
<target>این مقدار معتبر نیست.</target>
|
||||
<target>این مقدار معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="26">
|
||||
<source>This value is not a valid time.</source>
|
||||
<target>این مقدار یک زمان صحیح نیست.</target>
|
||||
<target>این مقدار یک زمان صحیح نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="27">
|
||||
<source>This value is not a valid URL.</source>
|
||||
<target>این یک URL معتبر نیست.</target>
|
||||
<target>این مقدار شامل یک URL معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="31">
|
||||
<source>The two values should be equal.</source>
|
||||
<target>دو مقدار باید برابر باشند.</target>
|
||||
<target>دو مقدار باید با یکدیگر برابر باشند.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="32">
|
||||
<source>The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.</source>
|
||||
<target>فایل بیش از اندازه بزرگ است. حداکثر اندازه مجاز برابر {{ limit }} {{ suffix }} است.</target>
|
||||
<target>فایل بیش از اندازه بزرگ است. حداکثر اندازه مجاز برابر با {{ limit }} {{ suffix }} می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="33">
|
||||
<source>The file is too large.</source>
|
||||
<target>فایل بیش از اندازه بزرگ است.</target>
|
||||
<target>فایل بیش از اندازه بزرگ می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="34">
|
||||
<source>The file could not be uploaded.</source>
|
||||
<target>بارگذاری فایل با شکست مواجه شد.</target>
|
||||
<target>بارگذاری فایل با شکست مواجه گردید.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="35">
|
||||
<source>This value should be a valid number.</source>
|
||||
@ -132,23 +132,23 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="36">
|
||||
<source>This file is not a valid image.</source>
|
||||
<target>این فایل یک تصویر نیست.</target>
|
||||
<target>این فایل یک تصویر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="37">
|
||||
<source>This is not a valid IP address.</source>
|
||||
<target>این مقدار یک IP معتبر نیست.</target>
|
||||
<target>این مقدار یک IP معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="38">
|
||||
<source>This value is not a valid language.</source>
|
||||
<target>این مقدار یک زبان صحیح نیست.</target>
|
||||
<target>این مقدار یک زبان صحیح نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="39">
|
||||
<source>This value is not a valid locale.</source>
|
||||
<target>این مقدار یک محل صحیح نیست.</target>
|
||||
<target>این مقدار یک محل صحیح نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="40">
|
||||
<source>This value is not a valid country.</source>
|
||||
<target>این مقدار یک کشور صحیح نیست.</target>
|
||||
<target>این مقدار یک کشور صحیح نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="41">
|
||||
<source>This value is already used.</source>
|
||||
@ -156,23 +156,23 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="42">
|
||||
<source>The size of the image could not be detected.</source>
|
||||
<target>اندازه تصویر قابل شناسایی نیست.</target>
|
||||
<target>اندازه تصویر قابل شناسایی نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="43">
|
||||
<source>The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px.</source>
|
||||
<target>طول تصویر بسیار بزرگ است ({{ width }}px). بشینه طول مجاز {{ max_width }}px است.</target>
|
||||
<target>طول تصویر بسیار بزرگ است ({{ width }}px). بشینه طول مجاز {{ max_width }}px می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="44">
|
||||
<source>The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.</source>
|
||||
<target>طول تصویر بسیار کوچک است ({{ width }}px). کمینه طول موردنظر {{ min_width }}px است.</target>
|
||||
<target>طول تصویر بسیار کوچک است ({{ width }}px). کمینه طول موردنظر {{ min_width }}px می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="45">
|
||||
<source>The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.</source>
|
||||
<target>ارتفاع تصویر بسیار بزرگ است ({{ height }}px). بشینه ارتفاع مجاز {{ max_height }}px است.</target>
|
||||
<target>ارتفاع تصویر بسیار بزرگ است ({{ height }}px). بشینه ارتفاع مجاز {{ max_height }}px می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="46">
|
||||
<source>The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px.</source>
|
||||
<target>ارتفاع تصویر بسیار کوچک است ({{ height }}px). کمینه ارتفاع موردنظر {{ min_height }}px است.</target>
|
||||
<target>ارتفاع تصویر بسیار کوچک است ({{ height }}px). کمینه ارتفاع موردنظر {{ min_height }}px می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="47">
|
||||
<source>This value should be the user's current password.</source>
|
||||
@ -184,67 +184,67 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="49">
|
||||
<source>The file was only partially uploaded.</source>
|
||||
<target>فایل به صورت جزیی بارگذاری شده است.</target>
|
||||
<target>پرونده به صورت جزیی بارگذاری گردیده است.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="50">
|
||||
<source>No file was uploaded.</source>
|
||||
<target>هیچ فایلی بارگذاری نشد.</target>
|
||||
<target>هیچ پرونده ای بارگذاری نگردیده است.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="51">
|
||||
<source>No temporary folder was configured in php.ini.</source>
|
||||
<target>فولدر موقت در php.ini پیکربندی نشده است.</target>
|
||||
<target>فولدر موقت در php.ini پیکربندی نگردیده است.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="52">
|
||||
<source>Cannot write temporary file to disk.</source>
|
||||
<target>فایل موقت را نمی توان در دیسک نوشت.</target>
|
||||
<target>فایل موقتی را نمی توان در دیسک نوشت.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="53">
|
||||
<source>A PHP extension caused the upload to fail.</source>
|
||||
<target>اکستنشن PHP موجب شد که بارگذاری فایل با شکست مواجه شود.</target>
|
||||
<target>یک اکستنشن PHP موجب شد که بارگذاری فایل با شکست مواجه گردد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="54">
|
||||
<source>This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.</source>
|
||||
<target>این مجموعه می بایست دارای {{ limit }} عنصر یا بیشتر باشد.|این مجموعه می بایست دارای {{ limit }} عنصر یا بیشتر باشد.</target>
|
||||
<target>این مجموعه می بایست دارای حداقل {{ limit }} عنصر یا بیشتر باشد.|این مجموعه می بایست دارای حداقل {{ limit }} عنصر یا بیشتر باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="55">
|
||||
<source>This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.</source>
|
||||
<target>این مجموعه می بایست دارای حداقل {{ limit }} عنصر یا کمتر باشد.|این مجموعه می بایست دارای {{ limit }} عنصر یا کمتر باشد.</target>
|
||||
<target>این مجموعه می بایست دارای حداکثر {{ limit }} عنصر یا کمتر باشد.|این مجموعه می بایست دارای حداکثر {{ limit }} عنصر یا کمتر باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="56">
|
||||
<source>This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.</source>
|
||||
<target>این مجموعه می بایست به طور دقیق دارا {{ limit }} عنصر باشد.|این مجموعه می بایست به طور دقیق دارای {{ limit }} قلم باشد.</target>
|
||||
<target>این مجموعه می بایست به طور دقیق دارای {{ limit }} عنصر باشد.|این مجموعه می بایست به طور دقیق دارای {{ limit }} عنصر باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="57">
|
||||
<source>Invalid card number.</source>
|
||||
<target>شماره کارت نامعتبر است.</target>
|
||||
<target>شماره کارت نامعتبر می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="58">
|
||||
<source>Unsupported card type or invalid card number.</source>
|
||||
<target>نوع کارت پشتیبانی نمی شود یا شماره کارت نامعتبر است.</target>
|
||||
<target>نوع کارت پشتیبانی نمی شود و یا شماره کارت نامعتبر می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="59">
|
||||
<source>This is not a valid International Bank Account Number (IBAN).</source>
|
||||
<target>این یک شماره حساب بین المللی بانک (IBAN) درست نیست.</target>
|
||||
<target>این یک شماره حساب بانک بین المللی معتبر نمی باشد (IBAN).</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="60">
|
||||
<source>This value is not a valid ISBN-10.</source>
|
||||
<target>این مقدار یک ISBN-10 درست نیست.</target>
|
||||
<target>این مقدار یک ISBN-10 معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="61">
|
||||
<source>This value is not a valid ISBN-13.</source>
|
||||
<target>این مقدار یک ISBN-13 درست نیست.</target>
|
||||
<target>این مقدار یک ISBN-13 معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="62">
|
||||
<source>This value is neither a valid ISBN-10 nor a valid ISBN-13.</source>
|
||||
<target>این مقدار یک ISBN-10 درست یا ISBN-13 درست نیست.</target>
|
||||
<target>این مقدار یک ISBN-10 صحیح و یا ISBN-13 معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="63">
|
||||
<source>This value is not a valid ISSN.</source>
|
||||
<target>این مقدار یک ISSN درست نیست.</target>
|
||||
<target>این مقدار یک ISSN معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="64">
|
||||
<source>This value is not a valid currency.</source>
|
||||
<target>این مقدار یک یکای پول درست نیست.</target>
|
||||
<target>این مقدار یک واحد پول معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="65">
|
||||
<source>This value should be equal to {{ compared_value }}.</source>
|
||||
@ -256,11 +256,11 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="67">
|
||||
<source>This value should be greater than or equal to {{ compared_value }}.</source>
|
||||
<target>این مقدار باید بزرگتر یا مساوی با {{ compared_value }} باشد.</target>
|
||||
<target>این مقدار باید بزرگتر و یا مساوی با {{ compared_value }} باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="68">
|
||||
<source>This value should be identical to {{ compared_value_type }} {{ compared_value }}.</source>
|
||||
<target>این مقدار باید با {{ compared_value_type }} {{ compared_value }} یکی باشد.</target>
|
||||
<target>این مقدار باید با {{ compared_value_type }} {{ compared_value }} یکسان باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="69">
|
||||
<source>This value should be less than {{ compared_value }}.</source>
|
||||
@ -268,7 +268,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="70">
|
||||
<source>This value should be less than or equal to {{ compared_value }}.</source>
|
||||
<target>این مقدار باید کمتر یا مساوی با {{ compared_value }} باشد.</target>
|
||||
<target>این مقدار باید کمتر و یا مساوی با {{ compared_value }} باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="71">
|
||||
<source>This value should not be equal to {{ compared_value }}.</source>
|
||||
@ -276,43 +276,43 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="72">
|
||||
<source>This value should not be identical to {{ compared_value_type }} {{ compared_value }}.</source>
|
||||
<target>این مقدار نباید {{ compared_value_type }} {{ compared_value }} یکی باشد.</target>
|
||||
<target>این مقدار نباید با {{ compared_value_type }} {{ compared_value }} یکسان باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="73">
|
||||
<source>The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}.</source>
|
||||
<target>ابعاد {{ ratio }} عکس بیش از حد بزرگ است.حداکثر ابعاد مجاز {{ max_ratio }} است.</target>
|
||||
<target>ابعاد {{ ratio }} عکس بیش از حد بزرگ است.حداکثر ابعاد مجاز {{ max_ratio }} می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="74">
|
||||
<source>The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}.</source>
|
||||
<target>ابعاد {{ ratio }} عکس بیش از حد کوچک است.حداقل ابعاد مجاز {{ min_ratio }} است.</target>
|
||||
<target>ابعاد {{ ratio }} عکس بیش از حد کوچک است.حداقل ابعاد مجاز {{ min_ratio }} می باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="75">
|
||||
<source>The image is square ({{ width }}x{{ height }}px). Square images are not allowed.</source>
|
||||
<target>این عکس مربع width }}x{{ height }}px}} می باشد.عکس مربع مجاز نمی باشد.</target>
|
||||
<target>این تصویر یک مربع width }}x{{ height }}px}} می باشد.تصویر مربع مجاز نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="76">
|
||||
<source>The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed.</source>
|
||||
<target>این عکس افقی width }}x{{ height }}px}} می باشد.عکس افقی مجاز نمی باشد.</target>
|
||||
<target>این تصویر افقی width }}x{{ height }}px}} می باشد.تصویر افقی مجاز نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="77">
|
||||
<source>The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed.</source>
|
||||
<target>این عکس عمودی width }}x{{ height }}px}} می باشد.عکس عمودی مجاز نمی باشد.</target>
|
||||
<target>این تصویر عمودی width }}x{{ height }}px}} می باشد.تصویر عمودی مجاز نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="78">
|
||||
<source>An empty file is not allowed.</source>
|
||||
<target>فایل خالی مجاز نمی باشد.</target>
|
||||
<target>پرونده خالی مجاز نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="79">
|
||||
<source>The host could not be resolved.</source>
|
||||
<target>هاست قابل حل نیست.</target>
|
||||
<target>میزبان قابل حل نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="80">
|
||||
<source>This value does not match the expected {{ charset }} charset.</source>
|
||||
<target>این مقدار مورد نظر نمی باشد. مقدار مورد نظر {{ charset }} می باشد.</target>
|
||||
<target>این مقدار مطابق با مقدار مورد انتظار {{ charset }} نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="81">
|
||||
<source>This is not a valid Business Identifier Code (BIC).</source>
|
||||
<target>این مقدار یک BIC درست نیست.</target>
|
||||
<target>این مقدار یک BIC معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="82">
|
||||
<source>Error</source>
|
||||
@ -320,7 +320,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="83">
|
||||
<source>This is not a valid UUID.</source>
|
||||
<target>این مقدار یک UUID درست نیست.</target>
|
||||
<target>این مقدار یک UUID معتبر نمی باشد.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="84">
|
||||
<source>This value should be a multiple of {{ compared_value }}.</source>
|
||||
@ -328,7 +328,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="85">
|
||||
<source>This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.</source>
|
||||
<target>این BIC با IBAN ارتباط ندارد.</target>
|
||||
<target>این BIC با IBAN ارتباطی ندارد.</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -56,6 +56,7 @@ trait WorkflowBuilderTrait
|
||||
$placesMetadata = [];
|
||||
$placesMetadata['c'] = [
|
||||
'bg_color' => 'DeepSkyBlue',
|
||||
'description' => 'My custom place description',
|
||||
];
|
||||
|
||||
$transitionsMetadata = new \SplObjectStorage();
|
||||
|
@ -17,7 +17,8 @@ skinparam agent {
|
||||
}
|
||||
state "a" <<initial>>
|
||||
state "b" <<marked>>
|
||||
state "c" <<DeepSkyBlue>>
|
||||
state "c" <<DeepSkyBlue>> as c
|
||||
c : My custom place description
|
||||
agent "t1"
|
||||
agent "t2"
|
||||
"a" -[#Purple]-> "t1": "<font color=Grey>My custom transition label 2</font>"
|
||||
|
@ -17,7 +17,8 @@ skinparam agent {
|
||||
}
|
||||
state "a" <<initial>>
|
||||
state "b"
|
||||
state "c" <<DeepSkyBlue>>
|
||||
state "c" <<DeepSkyBlue>> as c
|
||||
c : My custom place description
|
||||
agent "t1"
|
||||
agent "t2"
|
||||
"a" -[#Purple]-> "t1": "<font color=Grey>My custom transition label 2</font>"
|
||||
|
Reference in New Issue
Block a user