Merge branch '5.0'

* 5.0: (28 commits)
  [DoctrineBridge] Use new Types::* constants and support new json type
  Fix bad merge in README of Nexmo Notifier bridge
  [Debug][ErrorHandler] improved deprecation notices for methods new args and return type
  [BrowserKit] Nested file array prevents uploading file
  [ExpressionLanguage] Fixed collisions of character operators with object properties
  remove usage of already deleted Symfony\Component\EventDispatcher\Event
  [Notifier] Add correct tags for NullTransportFactory
  [Validator] Remove specific check for Valid targets
  [PhpUnitBridge] Use trait instead of extending deprecated class
  Fix versioned namespace clears
  fix remember me
  Use strict assertion in asset tests
  [DoctrineBridge][DoctrineExtractor] Fix indexBy with custom and some core types
  Do not rely on the current locale when dumping a Graphviz object
  fix typo
  [Ldap] force default network timeout
  [Config] don't throw on missing excluded paths
  Docs: Typo, grammar
  [Validator] Add the missing translations for the Polish ("pl") locale
  [PhpUnitBridge] Add compatibility to PHPUnit 9 #35662
  ...
This commit is contained in:
Nicolas Grekas 2020-02-24 16:14:17 +01:00
commit c231214e59
60 changed files with 575 additions and 142 deletions

View File

@ -268,3 +268,5 @@ abstract class DoctrineType extends AbstractType implements ResetInterface
return $this->entityLoaders[$hash] ?? ($this->entityLoaders[$hash] = $this->getLoader($manager, $queryBuilder, $class));
}
}
interface_exists(ObjectManager::class);

View File

@ -96,3 +96,5 @@ class EntityType extends DoctrineType
return [$parameter->getName(), $parameter->getType(), $parameter->getValue()];
}
}
interface_exists(ObjectManager::class);

View File

@ -103,7 +103,9 @@ class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeE
$typeOfField = $subMetadata->getTypeOfField($indexProperty);
}
$collectionKeyType = $this->getPhpType($typeOfField);
if (!$collectionKeyType = $this->getPhpType($typeOfField)) {
return null;
}
}
}
@ -123,39 +125,46 @@ class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeE
if ($metadata->hasField($property)) {
$typeOfField = $metadata->getTypeOfField($property);
if (!$builtinType = $this->getPhpType($typeOfField)) {
return null;
}
$nullable = $metadata instanceof ClassMetadataInfo && $metadata->isNullable($property);
switch ($typeOfField) {
case DBALType::DATE:
case DBALType::DATETIME:
case DBALType::DATETIMETZ:
case 'vardatetime':
case DBALType::TIME:
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')];
switch ($builtinType) {
case Type::BUILTIN_TYPE_OBJECT:
switch ($typeOfField) {
case DBALType::DATE:
case DBALType::DATETIME:
case DBALType::DATETIMETZ:
case 'vardatetime':
case DBALType::TIME:
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')];
case 'date_immutable':
case 'datetime_immutable':
case 'datetimetz_immutable':
case 'time_immutable':
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTimeImmutable')];
case 'date_immutable':
case 'datetime_immutable':
case 'datetimetz_immutable':
case 'time_immutable':
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTimeImmutable')];
case 'dateinterval':
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateInterval')];
case 'dateinterval':
return [new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateInterval')];
}
case DBALType::TARRAY:
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
break;
case Type::BUILTIN_TYPE_ARRAY:
switch ($typeOfField) {
case DBALType::TARRAY:
case DBALType::JSON_ARRAY:
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
case DBALType::SIMPLE_ARRAY:
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))];
case DBALType::JSON_ARRAY:
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
default:
$builtinType = $this->getPhpType($typeOfField);
return $builtinType ? [new Type($builtinType, $nullable)] : null;
case DBALType::SIMPLE_ARRAY:
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))];
}
}
return [new Type($builtinType, $nullable)];
}
return null;
@ -247,7 +256,22 @@ class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeE
return Type::BUILTIN_TYPE_RESOURCE;
case DBALType::OBJECT:
case DBALType::DATE:
case DBALType::DATETIME:
case DBALType::DATETIMETZ:
case 'vardatetime':
case DBALType::TIME:
case 'date_immutable':
case 'datetime_immutable':
case 'datetimetz_immutable':
case 'time_immutable':
case 'dateinterval':
return Type::BUILTIN_TYPE_OBJECT;
case DBALType::TARRAY:
case DBALType::SIMPLE_ARRAY:
case DBALType::JSON_ARRAY:
return Type::BUILTIN_TYPE_ARRAY;
}
return null;

View File

@ -153,3 +153,6 @@ class EntityUserProvider implements UserProviderInterface, PasswordUpgraderInter
return $this->getObjectManager()->getClassMetadata($this->classOrAlias);
}
}
interface_exists(ObjectManager::class);
interface_exists(ObjectRepository::class);

View File

@ -11,12 +11,14 @@
namespace Symfony\Bridge\Doctrine\Tests\PropertyInfo;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Type as DBALType;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor;
use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineGeneratedValue;
use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation;
use Symfony\Component\PropertyInfo\Type;
/**
@ -58,6 +60,8 @@ class DoctrineExtractorTest extends TestCase
'bar',
'indexedBar',
'indexedFoo',
'indexedByDt',
'indexedByCustomType',
],
$this->createExtractor()->getProperties('Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineDummy')
);
@ -149,6 +153,15 @@ class DoctrineExtractorTest extends TestCase
['simpleArray', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))]],
['customFoo', null],
['notMapped', null],
['indexedByDt', [new Type(
Type::BUILTIN_TYPE_OBJECT,
false,
Collection::class,
true,
new Type(Type::BUILTIN_TYPE_OBJECT),
new Type(Type::BUILTIN_TYPE_OBJECT, false, DoctrineRelation::class)
)]],
['indexedByCustomType', null],
];
}

View File

@ -112,4 +112,14 @@ class DoctrineDummy
private $bigint;
public $notMapped;
/**
* @OneToMany(targetEntity="DoctrineRelation", mappedBy="dt", indexBy="dt")
*/
protected $indexedByDt;
/**
* @OneToMany(targetEntity="DoctrineRelation", mappedBy="customType", indexBy="customType")
*/
private $indexedByCustomType;
}

View File

@ -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\Bridge\Doctrine\Tests\PropertyInfo\Fixtures;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\ManyToMany;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\OneToMany;
/**
* @Entity
*/
final class DoctrineDummy210 extends DoctrineDummy
{
/**
* @Column(type="json", nullable=true)
*/
private $json;
}

View File

@ -39,4 +39,14 @@ class DoctrineRelation
* @ManyToOne(targetEntity="DoctrineDummy", inversedBy="indexedFoo")
*/
protected $foo;
/**
* @Column(type="datetime")
*/
private $dt;
/**
* @Column(type="foo")
*/
private $customType;
}

View File

@ -0,0 +1,63 @@
<?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\Bridge\PhpUnit\Legacy;
use PHPUnit\TextUI\Command as BaseCommand;
use PHPUnit\TextUI\Configuration\Configuration;
use PHPUnit\TextUI\Configuration\Registry;
use PHPUnit\TextUI\TestRunner as BaseRunner;
use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
/**
* {@inheritdoc}
*
* @internal
*/
class CommandForV9 extends BaseCommand
{
/**
* {@inheritdoc}
*/
protected function createRunner(): BaseRunner
{
$this->arguments['listeners'] = isset($this->arguments['listeners']) ? $this->arguments['listeners'] : [];
$registeredLocally = false;
foreach ($this->arguments['listeners'] as $registeredListener) {
if ($registeredListener instanceof SymfonyTestsListener) {
$registeredListener->globalListenerDisabled();
$registeredLocally = true;
break;
}
}
if (isset($this->arguments['configuration'])) {
$configuration = $this->arguments['configuration'];
if (!$configuration instanceof Configuration) {
$configuration = Registry::getInstance()->get($this->arguments['configuration']);
}
foreach ($configuration->listeners() as $registeredListener) {
if ('Symfony\Bridge\PhpUnit\SymfonyTestsListener' === ltrim($registeredListener->className(), '\\')) {
$registeredLocally = true;
break;
}
}
}
if (!$registeredLocally) {
$this->arguments['listeners'][] = new SymfonyTestsListener();
}
return parent::createRunner();
}
}

View File

@ -11,8 +11,9 @@
namespace Symfony\Bridge\PhpUnit\Legacy;
use PHPUnit\Framework\BaseTestListener;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestListenerDefaultImplementation;
/**
* CoverageListener adds `@covers <className>` on each test when possible to
@ -22,8 +23,10 @@ use PHPUnit\Framework\Test;
*
* @internal
*/
class CoverageListenerForV6 extends BaseTestListener
class CoverageListenerForV6 implements TestListener
{
use TestListenerDefaultImplementation;
private $trait;
public function __construct(callable $sutFqcnResolver = null, $warningOnSutNotFound = false)

View File

@ -13,8 +13,10 @@ namespace Symfony\Bridge\PhpUnit\TextUI;
if (version_compare(\PHPUnit\Runner\Version::id(), '6.0.0', '<')) {
class_alias('Symfony\Bridge\PhpUnit\Legacy\CommandForV5', 'Symfony\Bridge\PhpUnit\TextUI\Command');
} else {
} elseif (version_compare(\PHPUnit\Runner\Version::id(), '9.0.0', '<')) {
class_alias('Symfony\Bridge\PhpUnit\Legacy\CommandForV6', 'Symfony\Bridge\PhpUnit\TextUI\Command');
} else {
class_alias('Symfony\Bridge\PhpUnit\Legacy\CommandForV9', 'Symfony\Bridge\PhpUnit\TextUI\Command');
}
if (false) {

View File

@ -24,7 +24,7 @@
"symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader"
},
"conflict": {
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0"
},
"autoload": {
"files": [ "bootstrap.php" ],

View File

@ -35,7 +35,7 @@ class TwigErrorRenderer implements ErrorRendererInterface
public function __construct(Environment $twig, HtmlErrorRenderer $fallbackErrorRenderer = null, $debug = false)
{
if (!\is_bool($debug) && !\is_callable($debug)) {
throw new \TypeError(sprintf('Argument 2 passed to %s() must be a boolean or a callable, %s given.', __METHOD__, \is_object($debug) ? \get_class($debug) : \gettype($debug)));
throw new \TypeError(sprintf('Argument 3 passed to %s() must be a boolean or a callable, %s given.', __METHOD__, \is_object($debug) ? \get_class($debug) : \gettype($debug)));
}
$this->twig = $twig;

View File

@ -47,7 +47,8 @@
</service>
<service id="notifier.transport_factory.null" class="Symfony\Component\Notifier\Transport\NullTransportFactory" parent="notifier.transport_factory.abstract">
<tag name="notifier.transport_factory" />
<tag name="chatter.transport_factory" />
<tag name="texter.transport_factory" />
</service>
</services>
</container>

View File

@ -37,7 +37,7 @@ class RequestStackContextTest extends TestCase
$requestStackContext = new RequestStackContext($requestStack);
$this->assertEquals($testBasePath, $requestStackContext->getBasePath());
$this->assertSame($testBasePath, $requestStackContext->getBasePath());
}
public function testIsSecureFalse()

View File

@ -24,7 +24,7 @@ class PackageTest extends TestCase
public function testGetUrl($version, $format, $path, $expected)
{
$package = new Package($version ? new StaticVersionStrategy($version, $format) : new EmptyVersionStrategy());
$this->assertEquals($expected, $package->getUrl($path));
$this->assertSame($expected, $package->getUrl($path));
}
public function getConfigs()
@ -50,6 +50,6 @@ class PackageTest extends TestCase
public function testGetVersion()
{
$package = new Package(new StaticVersionStrategy('v1'));
$this->assertEquals('v1', $package->getVersion('/foo'));
$this->assertSame('v1', $package->getVersion('/foo'));
}
}

View File

@ -24,13 +24,13 @@ class PackagesTest extends TestCase
$packages->setDefaultPackage($default = $this->getMockBuilder('Symfony\Component\Asset\PackageInterface')->getMock());
$packages->addPackage('a', $a = $this->getMockBuilder('Symfony\Component\Asset\PackageInterface')->getMock());
$this->assertEquals($default, $packages->getPackage());
$this->assertEquals($a, $packages->getPackage('a'));
$this->assertSame($default, $packages->getPackage());
$this->assertSame($a, $packages->getPackage('a'));
$packages = new Packages($default, ['a' => $a]);
$this->assertEquals($default, $packages->getPackage());
$this->assertEquals($a, $packages->getPackage('a'));
$this->assertSame($default, $packages->getPackage());
$this->assertSame($a, $packages->getPackage('a'));
}
public function testGetVersion()
@ -40,8 +40,8 @@ class PackagesTest extends TestCase
['a' => new Package(new StaticVersionStrategy('a'))]
);
$this->assertEquals('default', $packages->getVersion('/foo'));
$this->assertEquals('a', $packages->getVersion('/foo', 'a'));
$this->assertSame('default', $packages->getVersion('/foo'));
$this->assertSame('a', $packages->getVersion('/foo', 'a'));
}
public function testGetUrl()
@ -51,8 +51,8 @@ class PackagesTest extends TestCase
['a' => new Package(new StaticVersionStrategy('a'))]
);
$this->assertEquals('/foo?default', $packages->getUrl('/foo'));
$this->assertEquals('/foo?a', $packages->getUrl('/foo', 'a'));
$this->assertSame('/foo?default', $packages->getUrl('/foo'));
$this->assertSame('/foo?a', $packages->getUrl('/foo', 'a'));
}
public function testNoDefaultPackage()

View File

@ -23,7 +23,7 @@ class PathPackageTest extends TestCase
public function testGetUrl($basePath, $format, $path, $expected)
{
$package = new PathPackage($basePath, new StaticVersionStrategy('v1', $format));
$this->assertEquals($expected, $package->getUrl($path));
$this->assertSame($expected, $package->getUrl($path));
}
public function getConfigs()
@ -55,7 +55,7 @@ class PathPackageTest extends TestCase
{
$package = new PathPackage($basePath, new StaticVersionStrategy('v1', $format), $this->getContext($basePathRequest));
$this->assertEquals($expected, $package->getUrl($path));
$this->assertSame($expected, $package->getUrl($path));
}
public function getContextConfigs()
@ -83,7 +83,7 @@ class PathPackageTest extends TestCase
->willReturn('https://cdn.com/bar/main.css');
$package = new PathPackage('/subdirectory', $versionStrategy, $this->getContext('/bar'));
$this->assertEquals('https://cdn.com/bar/main.css', $package->getUrl('main.css'));
$this->assertSame('https://cdn.com/bar/main.css', $package->getUrl('main.css'));
}
private function getContext($basePath)

View File

@ -24,7 +24,7 @@ class UrlPackageTest extends TestCase
public function testGetUrl($baseUrls, $format, $path, $expected)
{
$package = new UrlPackage($baseUrls, new StaticVersionStrategy('v1', $format));
$this->assertEquals($expected, $package->getUrl($path));
$this->assertSame($expected, $package->getUrl($path));
}
public function getConfigs()
@ -65,7 +65,7 @@ class UrlPackageTest extends TestCase
{
$package = new UrlPackage($baseUrls, new StaticVersionStrategy('v1', $format), $this->getContext($secure));
$this->assertEquals($expected, $package->getUrl($path));
$this->assertSame($expected, $package->getUrl($path));
}
public function getContextConfigs()
@ -92,7 +92,7 @@ class UrlPackageTest extends TestCase
->willReturn('https://cdn.com/bar/main.css');
$package = new UrlPackage('https://example.com', $versionStrategy);
$this->assertEquals('https://cdn.com/bar/main.css', $package->getUrl('main.css'));
$this->assertSame('https://cdn.com/bar/main.css', $package->getUrl('main.css'));
}
public function testNoBaseUrls()

View File

@ -29,6 +29,6 @@ class EmptyVersionStrategyTest extends TestCase
$emptyVersionStrategy = new EmptyVersionStrategy();
$path = 'test-path';
$this->assertEquals($path, $emptyVersionStrategy->applyVersion($path));
$this->assertSame($path, $emptyVersionStrategy->applyVersion($path));
}
}

View File

@ -20,21 +20,21 @@ class JsonManifestVersionStrategyTest extends TestCase
{
$strategy = $this->createStrategy('manifest-valid.json');
$this->assertEquals('main.123abc.js', $strategy->getVersion('main.js'));
$this->assertSame('main.123abc.js', $strategy->getVersion('main.js'));
}
public function testApplyVersion()
{
$strategy = $this->createStrategy('manifest-valid.json');
$this->assertEquals('css/styles.555def.css', $strategy->getVersion('css/styles.css'));
$this->assertSame('css/styles.555def.css', $strategy->getVersion('css/styles.css'));
}
public function testApplyVersionWhenKeyDoesNotExistInManifest()
{
$strategy = $this->createStrategy('manifest-valid.json');
$this->assertEquals('css/other.css', $strategy->getVersion('css/other.css'));
$this->assertSame('css/other.css', $strategy->getVersion('css/other.css'));
}
public function testMissingManifestFileThrowsException()

View File

@ -21,7 +21,7 @@ class StaticVersionStrategyTest extends TestCase
$version = 'v1';
$path = 'test-path';
$staticVersionStrategy = new StaticVersionStrategy($version);
$this->assertEquals($version, $staticVersionStrategy->getVersion($path));
$this->assertSame($version, $staticVersionStrategy->getVersion($path));
}
/**
@ -31,7 +31,7 @@ class StaticVersionStrategyTest extends TestCase
{
$staticVersionStrategy = new StaticVersionStrategy($version, $format);
$formatted = sprintf($format ?: '%s?%s', $path, $version);
$this->assertEquals($formatted, $staticVersionStrategy->applyVersion($path));
$this->assertSame($formatted, $staticVersionStrategy->applyVersion($path));
}
public function getConfigs()

View File

@ -73,18 +73,9 @@ class HttpBrowser extends AbstractBrowser
}
$fields = $request->getParameters();
$hasFile = false;
foreach ($request->getFiles() as $name => $file) {
if (!isset($file['tmp_name'])) {
continue;
}
$hasFile = true;
$fields[$name] = DataPart::fromPath($file['tmp_name'], $file['name']);
}
if ($hasFile) {
$part = new FormDataPart($fields);
if ($uploadedFiles = $this->getUploadedFiles($request->getFiles())) {
$part = new FormDataPart($uploadedFiles);
return [$part->bodyToIterable(), $part->getPreparedHeaders()->toArray()];
}
@ -119,4 +110,26 @@ class HttpBrowser extends AbstractBrowser
return $headers;
}
/**
* Recursively go through the list. If the file has a tmp_name, convert it to a DataPart.
* Keep the original hierarchy.
*/
private function getUploadedFiles(array $files): array
{
$uploadedFiles = [];
foreach ($files as $name => $file) {
if (!\is_array($file)) {
return $uploadedFiles;
}
if (!isset($file['tmp_name'])) {
$uploadedFiles[$name] = $this->getUploadedFiles($file);
}
if (isset($file['tmp_name'])) {
$uploadedFiles[$name] = DataPart::fromPath($file['tmp_name'], $file['name']);
}
}
return $uploadedFiles;
}
}

View File

@ -27,17 +27,17 @@ class HttpBrowserTest extends AbstractBrowserTest
/**
* @dataProvider validContentTypes
*/
public function testRequestHeaders(array $request, array $exepectedCall)
public function testRequestHeaders(array $requestArguments, array $expectedArguments)
{
$client = $this->createMock(HttpClientInterface::class);
$client
->expects($this->once())
->method('request')
->with(...$exepectedCall)
->with(...$expectedArguments)
->willReturn($this->createMock(ResponseInterface::class));
$browser = new HttpBrowser($client);
$browser->request(...$request);
$browser->request(...$requestArguments);
}
public function validContentTypes()
@ -61,7 +61,7 @@ class HttpBrowserTest extends AbstractBrowserTest
];
}
public function testMultiPartRequest()
public function testMultiPartRequestWithSingleFile()
{
$client = $this->createMock(HttpClientInterface::class);
$client
@ -81,4 +81,90 @@ class HttpBrowserTest extends AbstractBrowserTest
file_put_contents($path, 'my_file');
$browser->request('POST', 'http://example.com/', [], ['file' => ['tmp_name' => $path, 'name' => 'foo']]);
}
public function testMultiPartRequestWithNormalFlatArray()
{
$client = $this->createMock(HttpClientInterface::class);
$this->expectClientToSendRequestWithFiles($client, ['file1_content', 'file2_content']);
$browser = new HttpBrowser($client);
$browser->request('POST', 'http://example.com/', [], [
'file1' => $this->getUploadedFile('file1'),
'file2' => $this->getUploadedFile('file2'),
]);
}
public function testMultiPartRequestWithNormalNestedArray()
{
$client = $this->createMock(HttpClientInterface::class);
$this->expectClientToSendRequestWithFiles($client, ['file1_content', 'file2_content']);
$browser = new HttpBrowser($client);
$browser->request('POST', 'http://example.com/', [], [
'level1' => [
'level2' => [
'file1' => $this->getUploadedFile('file1'),
'file2' => $this->getUploadedFile('file2'),
],
],
]);
}
public function testMultiPartRequestWithBracketedArray()
{
$client = $this->createMock(HttpClientInterface::class);
$this->expectClientToSendRequestWithFiles($client, ['file1_content', 'file2_content']);
$browser = new HttpBrowser($client);
$browser->request('POST', 'http://example.com/', [], [
'form[file1]' => $this->getUploadedFile('file1'),
'form[file2]' => $this->getUploadedFile('file2'),
]);
}
public function testMultiPartRequestWithInvalidItem()
{
$client = $this->createMock(HttpClientInterface::class);
$this->expectClientToSendRequestWithFiles($client, ['file1_content']);
$browser = new HttpBrowser($client);
$browser->request('POST', 'http://example.com/', [], [
'file1' => $this->getUploadedFile('file1'),
'file2' => 'INVALID',
]);
}
private function uploadFile(string $data): string
{
$path = tempnam(sys_get_temp_dir(), 'http');
file_put_contents($path, $data);
return $path;
}
private function getUploadedFile(string $name): array
{
return [
'tmp_name' => $this->uploadFile($name.'_content'),
'name' => $name.'_name',
];
}
protected function expectClientToSendRequestWithFiles(HttpClientInterface $client, $fileContents)
{
$client
->expects($this->once())
->method('request')
->with('POST', 'http://example.com/', $this->callback(function ($options) use ($fileContents) {
$this->assertStringContainsString('Content-Type: multipart/form-data', implode('', $options['headers']));
$this->assertInstanceOf('\Generator', $options['body']);
$body = implode('', iterator_to_array($options['body'], false));
foreach ($fileContents as $content) {
$this->assertStringContainsString($content, $body);
}
return true;
}))
->willReturn($this->createMock(ResponseInterface::class));
}
}

View File

@ -122,6 +122,12 @@ trait AbstractAdapterTrait
{
$this->deferred = [];
if ($cleared = $this->versioningIsEnabled) {
if ('' === $namespaceVersionToClear = $this->namespaceVersion) {
foreach ($this->doFetch([static::NS_SEPARATOR.$this->namespace]) as $v) {
$namespaceVersionToClear = $v;
}
}
$namespaceToClear = $this->namespace.$namespaceVersionToClear;
$namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5);
try {
$cleared = $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0);
@ -132,10 +138,12 @@ trait AbstractAdapterTrait
$this->namespaceVersion = $namespaceVersion;
$this->ids = [];
}
} else {
$namespaceToClear = $this->namespace.$prefix;
}
try {
return $this->doClear($this->namespace.$prefix) || $cleared;
return $this->doClear($namespaceToClear) || $cleared;
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to clear the cache: '.$e->getMessage(), ['exception' => $e]);

View File

@ -647,15 +647,7 @@ class Application implements ResetInterface
// filter out aliases for commands which are already on the list
if (\count($commands) > 1) {
$commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
if (isset($commandList[$name])) {
return $this->get($name);
}
foreach ($commands as $k => $nameOrAlias) {
if ($nameOrAlias === $name) {
return $this->get($nameOrAlias);
}
$commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) {
if (!$commandList[$nameOrAlias] instanceof Command) {
$commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
}
@ -664,14 +656,8 @@ class Application implements ResetInterface
$aliases[$nameOrAlias] = $commandName;
if ($commandName === $nameOrAlias || !\in_array($commandName, $commands)) {
continue;
}
unset($commands[$k]);
}
$commands = array_unique($commands);
return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
}));
}
if (\count($commands) > 1) {

View File

@ -32,10 +32,11 @@ class GraphvizDumper extends Dumper
{
private $nodes;
private $edges;
// All values should be strings
private $options = [
'graph' => ['ratio' => 'compress'],
'node' => ['fontsize' => 11, 'fontname' => 'Arial', 'shape' => 'record'],
'edge' => ['fontsize' => 9, 'fontname' => 'Arial', 'color' => 'grey', 'arrowhead' => 'open', 'arrowsize' => 0.5],
'node' => ['fontsize' => '11', 'fontname' => 'Arial', 'shape' => 'record'],
'edge' => ['fontsize' => '9', 'fontname' => 'Arial', 'color' => 'grey', 'arrowhead' => 'open', 'arrowsize' => '0.5'],
'node.instance' => ['fillcolor' => '#9999ff', 'style' => 'filled'],
'node.definition' => ['fillcolor' => '#eeeeee'],
'node.missing' => ['fillcolor' => '#ff9999', 'style' => 'filled'],

View File

@ -159,7 +159,7 @@ abstract class FileLoader extends BaseFileLoader
$excludePrefix = null;
$excludePatterns = $parameterBag->unescapeValue($parameterBag->resolveValue($excludePatterns));
foreach ($excludePatterns as $excludePattern) {
foreach ($this->glob($excludePattern, true, $resource, false, true) as $path => $info) {
foreach ($this->glob($excludePattern, true, $resource, true, true) as $path => $info) {
if (null === $excludePrefix) {
$excludePrefix = $resource->getPrefix();
}

View File

@ -136,6 +136,13 @@ class FileLoaderTest extends TestCase
],
array_keys($container->getAliases())
);
$loader->registerClasses(
new Definition(),
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\',
'Prototype/*',
'Prototype/NotExistingDir'
);
}
public function testRegisterClassesWithExcludeAsArray()

View File

@ -606,7 +606,7 @@ class DebugClassLoader
if ($canAddReturnType && 'docblock' === $this->patchTypes['force'] && false === strpos($method->getFileName(), \DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR)) {
$this->patchMethod($method, $returnType, $declaringFile, $normalizedType);
} elseif ('' !== $declaringClass && $this->patchTypes['deprecations']) {
$deprecations[] = sprintf('Method "%s::%s()" will return "%s" as of its next major version. Doing the same in child class "%s" will be required when upgrading.', $declaringClass, $method->name, $normalizedType, $className);
$deprecations[] = sprintf('Method "%s::%s()" will return "%s" as of its next major version. Doing the same in %s "%s" will be required when upgrading.', $declaringClass, $method->name, $normalizedType, interface_exists($declaringClass) ? 'implementation' : 'child class', $className);
}
}
}
@ -663,7 +663,7 @@ class DebugClassLoader
foreach ($matches as list(, $parameterType, $parameterName)) {
if (!isset($definedParameters[$parameterName])) {
$parameterType = trim($parameterType);
self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its parent class "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, $className);
self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its %s "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, interface_exists($className) ? 'interface' : 'parent class', $className);
}
}
}

View File

@ -289,12 +289,12 @@ class DebugClassLoaderTest extends TestCase
$this->assertSame([
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::quzMethod()" method will require a new "Quz $quz" argument in the next major version of its parent class "Symfony\Component\ErrorHandler\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::whereAmI()" method will require a new "bool $matrix" argument in the next major version of its parent class "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "$noType" argument in the next major version of its parent class "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable(\Throwable|null $reason, mixed $value) $callback" argument in the next major version of its parent class "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "string $param" argument in the next major version of its parent class "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable ($a, $b) $anotherOne" argument in the next major version of its parent class "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "Type$WithDollarIsStillAType $ccc" argument in the next major version of its parent class "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::whereAmI()" method will require a new "bool $matrix" argument in the next major version of its interface "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "$noType" argument in the next major version of its interface "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable(\Throwable|null $reason, mixed $value) $callback" argument in the next major version of its interface "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "string $param" argument in the next major version of its interface "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable ($a, $b) $anotherOne" argument in the next major version of its interface "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "Type$WithDollarIsStillAType $ccc" argument in the next major version of its interface "Symfony\Component\ErrorHandler\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\ErrorHandler\Tests\Fixtures\SubClassWithAnnotatedParameters::isSymfony()" method will require a new "true $yes" argument in the next major version of its parent class "Symfony\Component\ErrorHandler\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.',
], $deprecations);
}
@ -371,8 +371,8 @@ class DebugClassLoaderTest extends TestCase
$this->assertSame([
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeGrandParent::returnTypeGrandParent()" will return "string" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParentInterface::returnTypeParentInterface()" will return "string" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeInterface::returnTypeInterface()" will return "string" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParentInterface::returnTypeParentInterface()" will return "string" as of its next major version. Doing the same in implementation "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeInterface::returnTypeInterface()" will return "string" as of its next major version. Doing the same in implementation "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::oneNonNullableReturnableType()" will return "void" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::oneNonNullableReturnableTypeWithNull()" will return "void" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::oneNullableReturnableType()" will return "array" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',

View File

@ -16,7 +16,6 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\Event as LegacyEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\EventDispatcher\Event;
@ -141,7 +140,6 @@ class RegisterListenersPass implements CompilerPassInterface
|| !($type = $m->getParameters()[0]->getType())
|| $type->isBuiltin()
|| Event::class === ($name = $type->getName())
|| LegacyEvent::class === $name
) {
throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
}

View File

@ -71,7 +71,7 @@ class Lexer
// strings
$tokens[] = new Token(Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)), $cursor + 1);
$cursor += \strlen($match[0]);
} elseif (preg_match('/not in(?=[\s(])|\!\=\=|not(?=[\s(])|and(?=[\s(])|\=\=\=|\>\=|or(?=[\s(])|\<\=|\*\*|\.\.|in(?=[\s(])|&&|\|\||matches|\=\=|\!\=|\*|~|%|\/|\>|\||\!|\^|&|\+|\<|\-/A', $expression, $match, 0, $cursor)) {
} elseif (preg_match('/(?<=^|[\s(])not in(?=[\s(])|\!\=\=|(?<=^|[\s(])not(?=[\s(])|(?<=^|[\s(])and(?=[\s(])|\=\=\=|\>\=|(?<=^|[\s(])or(?=[\s(])|\<\=|\*\*|\.\.|(?<=^|[\s(])in(?=[\s(])|&&|\|\||(?<=^|[\s(])matches|\=\=|\!\=|\*|~|%|\/|\>|\||\!|\^|&|\+|\<|\-/A', $expression, $match, 0, $cursor)) {
// operators
$tokens[] = new Token(Token::OPERATOR_TYPE, $match[0], $cursor + 1);
$cursor += \strlen($match[0]);

View File

@ -15,9 +15,13 @@ arsort($operators);
$regex = [];
foreach ($operators as $operator => $length) {
// an operator that ends with a character must be followed by
// a whitespace or a parenthesis
$regex[] = preg_quote($operator, '/').(ctype_alpha($operator[$length - 1]) ? '(?=[\s(])' : '');
// Collisions of character operators:
// - an operator that begins with a character must have a space or a parenthesis before or starting at the beginning of a string
// - an operator that ends with a character must be followed by a whitespace or a parenthesis
$regex[] =
(ctype_alpha($operator[0]) ? '(?<=^|[\s(])' : '')
.preg_quote($operator, '/')
.(ctype_alpha($operator[$length - 1]) ? '(?=[\s(])' : '');
}
echo '/'.implode('|', $regex).'/A';

View File

@ -195,6 +195,17 @@ class ExpressionLanguageTest extends TestCase
$expressionLanguage->compile($expression, ['B' => 'b', 'a']);
}
public function testOperatorCollisions()
{
$expressionLanguage = new ExpressionLanguage();
$expression = 'foo.not in [bar]';
$compiled = $expressionLanguage->compile($expression, ['foo', 'bar']);
$this->assertSame('in_array($foo->not, [0 => $bar])', $compiled);
$result = $expressionLanguage->evaluate($expression, ['foo' => (object) ['not' => 'test'], 'bar' => 'test']);
$this->assertTrue($result);
}
/**
* @dataProvider getRegisterCallbacks
*/

View File

@ -114,6 +114,18 @@ class LexerTest extends TestCase
[new Token('string', '#foo', 1)],
'"#foo"',
],
[
[
new Token('name', 'foo', 1),
new Token('punctuation', '.', 4),
new Token('name', 'not', 5),
new Token('operator', 'in', 9),
new Token('punctuation', '[', 12),
new Token('name', 'bar', 13),
new Token('punctuation', ']', 16),
],
'foo.not in [bar]',
],
];
}
}

View File

@ -53,6 +53,9 @@ class ParserTest extends TestCase
$arguments->addElement(new Node\ConstantNode(2));
$arguments->addElement(new Node\ConstantNode(true));
$arrayNode = new Node\ArrayNode();
$arrayNode->addElement(new Node\NameNode('bar'));
return [
[
new Node\NameNode('a'),
@ -151,6 +154,36 @@ class ParserTest extends TestCase
'bar',
['foo' => 'bar'],
],
// Operators collisions
[
new Node\BinaryNode(
'in',
new Node\GetAttrNode(
new Node\NameNode('foo'),
new Node\ConstantNode('not', true),
new Node\ArgumentsNode(),
Node\GetAttrNode::PROPERTY_CALL
),
$arrayNode
),
'foo.not in [bar]',
['foo', 'bar'],
],
[
new Node\BinaryNode(
'or',
new Node\UnaryNode('not', new Node\NameNode('foo')),
new Node\GetAttrNode(
new Node\NameNode('foo'),
new Node\ConstantNode('not', true),
new Node\ArgumentsNode(),
Node\GetAttrNode::PROPERTY_CALL
)
),
'not foo or foo.not',
['foo'],
],
];
}

View File

@ -55,6 +55,8 @@ class CachingHttpClient implements HttpClientInterface
unset($defaultOptions['allow_revalidate']);
unset($defaultOptions['stale_while_revalidate']);
unset($defaultOptions['stale_if_error']);
unset($defaultOptions['trace_level']);
unset($defaultOptions['trace_header']);
if ($defaultOptions) {
[, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions);

View File

@ -85,7 +85,7 @@ class ControllerResolver implements ControllerResolverInterface
try {
$callable = $this->createController($controller);
} catch (\InvalidArgumentException $e) {
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $e->getMessage()));
throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $e->getMessage()), 0, $e);
}
if (!\is_callable($callable)) {

View File

@ -64,6 +64,9 @@ class DebugHandlersListener implements EventSubscriberInterface
*/
public function configure(object $event = null)
{
if ($event instanceof ConsoleEvent && !\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
return;
}
if (!$event instanceof KernelEvent ? !$this->firstCall : !$event->isMasterRequest()) {
return;
}
@ -144,7 +147,7 @@ class DebugHandlersListener implements EventSubscriberInterface
{
$events = [KernelEvents::REQUEST => ['configure', 2048]];
if ('cli' === \PHP_SAPI && \defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) {
if (\defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) {
$events[ConsoleEvents::COMMAND] = ['configure', 2048];
}

View File

@ -116,6 +116,10 @@ class Connection extends AbstractConnection
$options->setDefault('debug_level', 7);
}
if (!isset($parent['network_timeout'])) {
$options->setDefault('network_timeout', ini_get('default_socket_timeout'));
}
$options->setDefaults([
'protocol_version' => $parent['version'],
'referrals' => $parent['referrals'],

View File

@ -3,19 +3,6 @@ Nexmo Notifier
Provides Nexmo integration for Symfony Notifier.
Getting Started
---------------
```
$ composer install symfony/debug
```
```php
use Symfony\Component\Debug\Debug;
Debug::enable();
```
Resources
---------

View File

@ -18,6 +18,7 @@ use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Routing\Annotation\Route as RouteAnnotation;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouteCompiler;
/**
* AnnotationClassLoader loads routing information from a PHP class and its methods.
@ -205,6 +206,7 @@ abstract class AnnotationClassLoader implements LoaderInterface
$this->configureRoute($route, $class, $method, $annot);
if (0 !== $locale) {
$route->setDefault('_locale', $locale);
$route->setRequirement('_locale', preg_quote($locale, RouteCompiler::REGEX_DELIMITER));
$route->setDefault('_canonical_route', $name);
$collection->add($name.'.'.$locale, $route, $priority);
} else {

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Routing\Loader\Configurator\Traits;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouteCompiler;
/**
* @internal
@ -63,6 +64,7 @@ trait LocalizedRouteTrait
$routes->add($name.'.'.$locale, $route = $this->createRoute($path));
$collection->add($namePrefix.$name.'.'.$locale, $route);
$route->setDefault('_locale', $locale);
$route->setRequirement('_locale', preg_quote($locale, RouteCompiler::REGEX_DELIMITER));
$route->setDefault('_canonical_route', $namePrefix.$name);
}

View File

@ -17,6 +17,7 @@ use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait;
use Symfony\Component\Routing\Loader\Configurator\Traits\PrefixTrait;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouteCompiler;
/**
* XmlFileLoader loads XML routing files.

View File

@ -16,6 +16,7 @@ use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait;
use Symfony\Component\Routing\Loader\Configurator\Traits\PrefixTrait;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouteCompiler;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Yaml\Yaml;

View File

@ -121,6 +121,9 @@ class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
$this->assertCount(2, $routes);
$this->assertEquals('/path', $routes->get('action.en')->getPath());
$this->assertEquals('/pad', $routes->get('action.nl')->getPath());
$this->assertEquals('nl', $routes->get('action.nl')->getRequirement('_locale'));
$this->assertEquals('en', $routes->get('action.en')->getRequirement('_locale'));
}
public function testLocalizedPathRoutesWithExplicitPathPropety()

View File

@ -229,11 +229,11 @@ class PhpFileLoaderTest extends TestCase
$expectedCollection = new RouteCollection();
$expectedCollection->add('foo.en', (new Route('/glish/foo'))->setDefaults(['_locale' => 'en', '_canonical_route' => 'foo']));
$expectedCollection->add('bar.en', (new Route('/glish/bar'))->setDefaults(['_locale' => 'en', '_canonical_route' => 'bar']));
$expectedCollection->add('baz.en', (new Route('/baz'))->setDefaults(['_locale' => 'en', '_canonical_route' => 'baz']));
$expectedCollection->add('c_foo.fr', (new Route('/ench/pub/foo'))->setDefaults(['_locale' => 'fr', '_canonical_route' => 'c_foo']));
$expectedCollection->add('c_bar.fr', (new Route('/ench/pub/bar'))->setDefaults(['_locale' => 'fr', '_canonical_route' => 'c_bar']));
$expectedCollection->add('foo.en', (new Route('/glish/foo'))->setDefaults(['_locale' => 'en', '_canonical_route' => 'foo'])->setRequirement('_locale', 'en'));
$expectedCollection->add('bar.en', (new Route('/glish/bar'))->setDefaults(['_locale' => 'en', '_canonical_route' => 'bar'])->setRequirement('_locale', 'en'));
$expectedCollection->add('baz.en', (new Route('/baz'))->setDefaults(['_locale' => 'en', '_canonical_route' => 'baz'])->setRequirement('_locale', 'en'));
$expectedCollection->add('c_foo.fr', (new Route('/ench/pub/foo'))->setDefaults(['_locale' => 'fr', '_canonical_route' => 'c_foo'])->setRequirement('_locale', 'fr'));
$expectedCollection->add('c_bar.fr', (new Route('/ench/pub/bar'))->setDefaults(['_locale' => 'fr', '_canonical_route' => 'c_bar'])->setRequirement('_locale', 'fr'));
$expectedCollection->addResource(new FileResource(realpath(__DIR__.'/../Fixtures/php_dsl_sub_i18n.php')));
$expectedCollection->addResource(new FileResource(realpath(__DIR__.'/../Fixtures/php_dsl_i18n.php')));

View File

@ -185,6 +185,9 @@ class XmlFileLoaderTest extends TestCase
$this->assertEquals('/le-prefix/le-suffix', $routeCollection->get('imported.fr')->getPath());
$this->assertEquals('/the-prefix/suffix', $routeCollection->get('imported.en')->getPath());
$this->assertEquals('fr', $routeCollection->get('imported.fr')->getRequirement('_locale'));
$this->assertEquals('en', $routeCollection->get('imported.en')->getRequirement('_locale'));
}
public function testLocalizedImportsOfNotLocalizedRoutes()

View File

@ -321,6 +321,9 @@ class YamlFileLoaderTest extends TestCase
$this->assertCount(2, $routes);
$this->assertEquals('/nl/voorbeeld', $routes->get('imported.nl')->getPath());
$this->assertEquals('/en/example', $routes->get('imported.en')->getPath());
$this->assertEquals('nl', $routes->get('imported.nl')->getRequirement('_locale'));
$this->assertEquals('en', $routes->get('imported.en')->getRequirement('_locale'));
}
public function testImportingNonLocalizedRoutesWithLocales()

View File

@ -15,7 +15,9 @@ use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Exception\LogicException;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class RememberMeAuthenticationProvider implements AuthenticationProviderInterface
{
@ -48,6 +50,11 @@ class RememberMeAuthenticationProvider implements AuthenticationProviderInterfac
}
$user = $token->getUser();
if (!$token->getUser() instanceof UserInterface) {
throw new LogicException(sprintf('Method "%s::getUser()" must return a "%s" instance, "%s" returned.', \get_class($token), UserInterface::class, \is_object($user) ? \get_class($user) : \gettype($user)));
}
$this->userChecker->checkPreAuth($user);
$this->userChecker->checkPostAuth($user);

View File

@ -13,7 +13,9 @@ namespace Symfony\Component\Security\Core\Tests\Authentication\Provider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Authentication\Provider\RememberMeAuthenticationProvider;
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
use Symfony\Component\Security\Core\Exception\DisabledException;
use Symfony\Component\Security\Core\User\User;
class RememberMeAuthenticationProviderTest extends TestCase
{
@ -23,6 +25,7 @@ class RememberMeAuthenticationProviderTest extends TestCase
$this->assertTrue($provider->supports($this->getSupportedToken()));
$this->assertFalse($provider->supports($this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock()));
$this->assertFalse($provider->supports($this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\RememberMeToken')->disableOriginalConstructor()->getMock()));
}
public function testAuthenticateWhenTokenIsNotSupported()
@ -44,6 +47,17 @@ class RememberMeAuthenticationProviderTest extends TestCase
$provider->authenticate($token);
}
public function testAuthenticateThrowsOnNonUserInterfaceInstance()
{
$this->expectException('Symfony\Component\Security\Core\Exception\LogicException');
$this->expectExceptionMessage('Method "Symfony\Component\Security\Core\Authentication\Token\RememberMeToken::getUser()" must return a "Symfony\Component\Security\Core\User\UserInterface" instance, "string" returned.');
$provider = $this->getProvider();
$token = new RememberMeToken(new User('dummyuser', null), 'foo', 'test');
$token->setUser('stringish-user');
$provider->authenticate($token);
}
public function testAuthenticateWhenPreChecksFails()
{
$this->expectException('Symfony\Component\Security\Core\Exception\DisabledException');

View File

@ -19,10 +19,10 @@ namespace Symfony\Component\Security\Core\User;
* password (for checking against a submitted password), assigning roles
* and so on.
*
* Regardless of how your user are loaded or where they come from (a database,
* configuration, web service, etc), you will have a class that implements
* this interface. Objects that implement this interface are created and
* loaded by different objects that implement UserProviderInterface
* Regardless of how your users are loaded or where they come from (a database,
* configuration, web service, etc.), you will have a class that implements
* this interface. Objects that implement this interface are created and
* loaded by different objects that implement UserProviderInterface.
*
* @see UserProviderInterface
*

View File

@ -86,7 +86,7 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
return $token;
}
// this AccountExpiredException causes the user to be logged out
// this causes the user to be logged out
throw new AuthenticationExpiredException();
}

View File

@ -14,7 +14,6 @@ namespace Symfony\Component\Validator\Mapping;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\GroupSequence;
use Symfony\Component\Validator\Constraints\Traverse;
use Symfony\Component\Validator\Constraints\Valid;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Symfony\Component\Validator\Exception\GroupDefinitionException;
@ -178,10 +177,6 @@ class ClassMetadata extends GenericMetadata implements ClassMetadataInterface
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on classes.', \get_class($constraint)));
}
if ($constraint instanceof Valid) {
throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on classes.', \get_class($constraint)));
}
if ($constraint instanceof Traverse) {
if ($constraint->traverse) {
// If traverse is true, traversal should be explicitly enabled

View File

@ -330,10 +330,46 @@
<source>This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.</source>
<target>Ten kod BIC (Business Identifier Code) nie jest powiązany z międzynarodowym numerem rachunku bankowego (IBAN) {{ iban }}.</target>
</trans-unit>
<trans-unit id="86">
<source>This value should be valid JSON.</source>
<target>Ta wartość powinna być prawidłowym formatem JSON.</target>
</trans-unit>
<trans-unit id="87">
<source>This collection should contain only unique elements.</source>
<target>Ten zbiór powinien zawierać tylko unikalne elementy.</target>
</trans-unit>
<trans-unit id="88">
<source>This value should be positive.</source>
<target>Ta wartość powinna być dodatnia.</target>
</trans-unit>
<trans-unit id="89">
<source>This value should be either positive or zero.</source>
<target>Ta wartość powinna być dodatnia lub równa zero.</target>
</trans-unit>
<trans-unit id="90">
<source>This value should be negative.</source>
<target>Ta wartość powinna być ujemna.</target>
</trans-unit>
<trans-unit id="91">
<source>This value should be either negative or zero.</source>
<target>Ta wartość powinna być ujemna lub równa zero.</target>
</trans-unit>
<trans-unit id="92">
<source>This value is not a valid timezone.</source>
<target>Ta wartość nie jest prawidłową strefą czasową.</target>
</trans-unit>
<trans-unit id="93">
<source>This password has been leaked in a data breach, it must not be used. Please use another password.</source>
<target>To hasło wyciekło w wyniku naruszenia danych i nie może być użyte. Proszę użyć innego hasła.</target>
</trans-unit>
<trans-unit id="94">
<source>This value should be between {{ min }} and {{ max }}.</source>
<target>Ta wartość powinna być pomiędzy {{ min }} a {{ max }}.</target>
</trans-unit>
<trans-unit id="95">
<source>This value is not a valid hostname.</source>
<target>Ta wartość nie jest prawidłową nazwą hosta.</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -35,7 +35,11 @@ class DateCaster
.($location ? ($d->format('I') ? "\nDST On" : "\nDST Off") : '')
;
$a = [];
unset(
$a[Caster::PREFIX_DYNAMIC.'date'],
$a[Caster::PREFIX_DYNAMIC.'timezone'],
$a[Caster::PREFIX_DYNAMIC.'timezone_type']
);
$a[$prefix.'date'] = new ConstStub(self::formatDateTime($d, $location ? ' e (P)' : ' P'), $title);
$stub->class .= $d->format(' @U');

View File

@ -16,6 +16,7 @@ use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Caster\DateCaster;
use Symfony\Component\VarDumper\Cloner\Stub;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
use Symfony\Component\VarDumper\Tests\Fixtures\DateTimeChild;
/**
* @author Dany Maillard <danymaillard93b@gmail.com>
@ -47,7 +48,7 @@ EODUMP;
{
$stub = new Stub();
$date = new \DateTime($time, new \DateTimeZone($timezone));
$cast = DateCaster::castDateTime($date, ['foo' => 'bar'], $stub, false, 0);
$cast = DateCaster::castDateTime($date, Caster::castObject($date, \DateTime::class), $stub, false, 0);
$xDump = <<<EODUMP
array:1 [
@ -89,6 +90,40 @@ EODUMP;
];
}
public function testCastDateTimeWithAdditionalChildProperty()
{
$stub = new Stub();
$date = new DateTimeChild('2020-02-13 00:00:00.123456', new \DateTimeZone('Europe/Paris'));
$objectCast = Caster::castObject($date, DateTimeChild::class);
$dateCast = DateCaster::castDateTime($date, $objectCast, $stub, false, 0);
$xDate = '2020-02-13 00:00:00.123456 Europe/Paris (+01:00)';
$xInfo = 'Thursday, February 13, 2020%Afrom now';
$xDump = <<<EODUMP
array:2 [
"\\x00Symfony\Component\VarDumper\Tests\Fixtures\DateTimeChild\\x00addedProperty" => "foo"
"\\x00~\\x00date" => $xDate
]
EODUMP;
$this->assertDumpEquals($xDump, $dateCast);
$xDump = <<<EODUMP
Symfony\Component\VarDumper\Caster\ConstStub {
+type: 1
+class: "$xDate"
+value: "%A$xInfo%A"
+cut: 0
+handle: 0
+refCount: 0
+position: 0
+attr: []
}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $dateCast["\0~\0date"]);
}
/**
* @dataProvider provideIntervals
*/

View File

@ -0,0 +1,8 @@
<?php
namespace Symfony\Component\VarDumper\Tests\Fixtures;
class DateTimeChild extends \DateTime
{
private $addedProperty = 'foo';
}

View File

@ -26,10 +26,11 @@ use Symfony\Component\Workflow\Marking;
*/
class GraphvizDumper implements DumperInterface
{
// All values should be strings
protected static $defaultOptions = [
'graph' => ['ratio' => 'compress', 'rankdir' => 'LR'],
'node' => ['fontsize' => 9, 'fontname' => 'Arial', 'color' => '#333333', 'fillcolor' => 'lightblue', 'fixedsize' => 'false', 'width' => 1],
'edge' => ['fontsize' => 9, 'fontname' => 'Arial', 'color' => '#333333', 'arrowhead' => 'normal', 'arrowsize' => 0.5],
'node' => ['fontsize' => '9', 'fontname' => 'Arial', 'color' => '#333333', 'fillcolor' => 'lightblue', 'fixedsize' => 'false', 'width' => '1'],
'edge' => ['fontsize' => '9', 'fontname' => 'Arial', 'color' => '#333333', 'arrowhead' => 'normal', 'arrowsize' => '0.5'],
];
/**