From dfa7f5020e1274870ee815bb536d37b0e61d8046 Mon Sep 17 00:00:00 2001 From: Vincent Composieux Date: Mon, 29 Aug 2016 20:28:05 +0200 Subject: [PATCH 01/88] [Security] Fixed roles serialization on token from user object --- .../Core/Authentication/Token/AbstractToken.php | 2 +- .../Provider/UserAuthenticationProviderTest.php | 2 +- .../Authentication/Token/AbstractTokenTest.php | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php index 7538648b1329f..48a4e52a48bee 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php @@ -150,7 +150,7 @@ public function serialize() array( is_object($this->user) ? clone $this->user : $this->user, $this->authenticated, - $this->roles, + array_map(function ($role) { return clone $role; }, $this->roles), $this->attributes, ) ); diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php index 05030543e6410..6b6a6615161b1 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php @@ -220,7 +220,7 @@ public function testAuthenticateWithPreservingRoleSwitchUserRole() $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $authToken); $this->assertSame($user, $authToken->getUser()); $this->assertContains(new Role('ROLE_FOO'), $authToken->getRoles(), '', false, false); - $this->assertContains($switchUserRole, $authToken->getRoles()); + $this->assertContains($switchUserRole, $authToken->getRoles(), '', false, false); $this->assertEquals('foo', $authToken->getCredentials()); $this->assertEquals(array('foo' => 'bar'), $authToken->getAttributes(), '->authenticate() copies token attributes'); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php index 1a786d7c4543e..2eff28e009b5d 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\SwitchUserRole; +use Symfony\Component\Security\Core\User\User; class TestUser { @@ -87,7 +88,7 @@ public function testEraseCredentials() public function testSerialize() { - $token = $this->getToken(array('ROLE_FOO')); + $token = $this->getToken(array('ROLE_FOO', new Role('ROLE_BAR'))); $token->setAttributes(array('foo' => 'bar')); $uToken = unserialize(serialize($token)); @@ -96,6 +97,19 @@ public function testSerialize() $this->assertEquals($token->getAttributes(), $uToken->getAttributes()); } + public function testSerializeWithRoleObjects() + { + $user = new User('name', 'password', array(new Role('ROLE_FOO'), new Role('ROLE_BAR'))); + $token = new ConcreteToken($user, $user->getRoles()); + + $serialized = serialize($token); + $unserialized = unserialize($serialized); + + $roles = $unserialized->getRoles(); + + $this->assertEquals($roles, $user->getRoles()); + } + public function testSerializeParent() { $user = new TestUser('fabien'); From 9a2b2de64fffdf70220de58509d0999555c7ba77 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Mar 2017 11:02:41 +0100 Subject: [PATCH 02/88] [HttpFoundation] Fix Request::getHost() when having several hosts in X_FORWARDED_HOST --- src/Symfony/Component/HttpFoundation/Request.php | 6 +++--- src/Symfony/Component/HttpFoundation/Tests/RequestTest.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 697bc6c3c3e13..f549f8019eeaf 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -962,7 +962,7 @@ public function getPort() { if ($this->isFromTrustedProxy()) { if (self::$trustedHeaders[self::HEADER_CLIENT_PORT] && $port = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PORT])) { - return $port; + return (int) $port; } if (self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && 'https' === $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO], 'http')) { @@ -1211,9 +1211,9 @@ public function isSecure() public function getHost() { if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_HOST] && $host = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_HOST])) { - $elements = explode(',', $host); + $elements = explode(',', $host, 2); - $host = $elements[count($elements) - 1]; + $host = $elements[0]; } elseif (!$host = $this->headers->get('HOST')) { if (!$host = $this->server->get('SERVER_NAME')) { $host = $this->server->get('SERVER_ADDR', ''); diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 9000eb622b118..f23a5b439b5e5 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1631,7 +1631,7 @@ public function testTrustedProxies() $request = Request::create('http://example.com/'); $request->server->set('REMOTE_ADDR', '3.3.3.3'); $request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2'); - $request->headers->set('X_FORWARDED_HOST', 'foo.example.com, real.example.com:8080'); + $request->headers->set('X_FORWARDED_HOST', 'foo.example.com:1234, real.example.com:8080'); $request->headers->set('X_FORWARDED_PROTO', 'https'); $request->headers->set('X_FORWARDED_PORT', 443); $request->headers->set('X_MY_FOR', '3.3.3.3, 4.4.4.4'); @@ -1662,7 +1662,7 @@ public function testTrustedProxies() // trusted proxy via setTrustedProxies() Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2')); $this->assertEquals('1.1.1.1', $request->getClientIp()); - $this->assertEquals('real.example.com', $request->getHost()); + $this->assertEquals('foo.example.com', $request->getHost()); $this->assertEquals(443, $request->getPort()); $this->assertTrue($request->isSecure()); From 5af9315684a1af6349a6e75d5315d3feb563b5e7 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 10 Mar 2017 10:53:31 -0800 Subject: [PATCH 03/88] bumped Symfony version to 3.2.7 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index f02c9a9cbde67..d056a43acc37e 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '3.2.6'; - const VERSION_ID = 30206; + const VERSION = '3.2.7-DEV'; + const VERSION_ID = 30207; const MAJOR_VERSION = 3; const MINOR_VERSION = 2; - const RELEASE_VERSION = 6; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 7; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '07/2017'; const END_OF_LIFE = '01/2018'; From ed211e9c74e50ec4eb3d7a78718563c06b59b17e Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Thu, 9 Mar 2017 22:37:49 +0200 Subject: [PATCH 04/88] [Form] Choice type int values (BC Fix) --- .../Form/Extension/Core/Type/ChoiceType.php | 4 ++-- .../Tests/Extension/Core/Type/ChoiceTypeTest.php | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index b4b820ef263e9..1392c81a59f93 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -171,8 +171,8 @@ public function buildForm(FormBuilderInterface $builder, array $options) } foreach ($data as $v) { - if (null !== $v && !is_string($v)) { - throw new TransformationFailedException('All choices submitted must be NULL or strings.'); + if (null !== $v && !is_string($v) && !is_int($v)) { + throw new TransformationFailedException('All choices submitted must be NULL, strings or ints.'); } } }, 256); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index b9097afdb61b9..983397b09d624 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -1689,6 +1689,19 @@ public function testSubmitMultipleExpandedNumericChoices() $this->assertNull($form[4]->getViewData()); } + public function testSubmitMultipleChoicesInts() + { + $form = $this->factory->create(static::TESTED_TYPE, null, array( + 'multiple' => true, + 'choices' => array_flip($this->numericChoicesFlipped), + 'choices_as_values' => true, + )); + + $form->submit(array(1, 2)); + + $this->assertTrue($form->isSynchronized()); + } + public function testSingleSelectedObjectChoices() { $view = $this->factory->create(static::TESTED_TYPE, $this->objectChoices[3], array( @@ -2306,7 +2319,7 @@ public function testSubmitInvalidNestedValue($multiple, $expanded, $submissionDa $form->submit($submissionData); $this->assertFalse($form->isSynchronized()); - $this->assertEquals('All choices submitted must be NULL or strings.', $form->getTransformationFailure()->getMessage()); + $this->assertEquals('All choices submitted must be NULL, strings or ints.', $form->getTransformationFailure()->getMessage()); } public function invalidNestedValueTestMatrix() From 8f0edfb10fdeef00085874c0f179825ac429bd2d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 10 Mar 2017 23:26:11 +0100 Subject: [PATCH 05/88] [VarDumper] Add missing isset() checks in some casters --- src/Symfony/Component/VarDumper/Caster/Caster.php | 6 ++++-- .../Component/VarDumper/Caster/ExceptionCaster.php | 8 ++++++-- src/Symfony/Component/VarDumper/Caster/RedisCaster.php | 6 ++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Caster/Caster.php b/src/Symfony/Component/VarDumper/Caster/Caster.php index 5428fecc2b27b..5749e0762a684 100644 --- a/src/Symfony/Component/VarDumper/Caster/Caster.php +++ b/src/Symfony/Component/VarDumper/Caster/Caster.php @@ -132,8 +132,10 @@ public static function filter(array $a, $filter, array $listedProperties = array public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, $isNested) { - $stub->class .= '('.$a['__PHP_Incomplete_Class_Name'].')'; - unset($a['__PHP_Incomplete_Class_Name']); + if (isset($a['__PHP_Incomplete_Class_Name'])) { + $stub->class .= '('.$a['__PHP_Incomplete_Class_Name'].')'; + unset($a['__PHP_Incomplete_Class_Name']); + } return $a; } diff --git a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php index aa32d8b90bb98..f522ae269aa4e 100644 --- a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php @@ -218,7 +218,9 @@ private static function filterExceptionArray($xClass, array $a, $xPrefix, $filte } if (!($filter & Caster::EXCLUDE_VERBOSE)) { - self::traceUnshift($trace, $xClass, $a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); + if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { + self::traceUnshift($trace, $xClass, $a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); + } $a[$xPrefix.'trace'] = new TraceStub($trace, self::$traceArgs); } if (empty($a[$xPrefix.'previous'])) { @@ -226,7 +228,9 @@ private static function filterExceptionArray($xClass, array $a, $xPrefix, $filte } unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']); - $a[Caster::PREFIX_PROTECTED.'file'] = new LinkStub($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); + if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { + $a[Caster::PREFIX_PROTECTED.'file'] = new LinkStub($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); + } return $a; } diff --git a/src/Symfony/Component/VarDumper/Caster/RedisCaster.php b/src/Symfony/Component/VarDumper/Caster/RedisCaster.php index 7275a7d2c7f88..07a3a1b091126 100644 --- a/src/Symfony/Component/VarDumper/Caster/RedisCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/RedisCaster.php @@ -31,8 +31,10 @@ public static function castRedis(\Redis $c, array $a, Stub $stub, $isNested) $prefix = Caster::PREFIX_VIRTUAL; if (defined('HHVM_VERSION_ID')) { - $ser = $a[Caster::PREFIX_PROTECTED.'serializer']; - $a[Caster::PREFIX_PROTECTED.'serializer'] = isset(self::$serializer[$ser]) ? new ConstStub(self::$serializer[$ser], $ser) : $ser; + if (isset($a[Caster::PREFIX_PROTECTED.'serializer'])) { + $ser = $a[Caster::PREFIX_PROTECTED.'serializer']; + $a[Caster::PREFIX_PROTECTED.'serializer'] = isset(self::$serializer[$ser]) ? new ConstStub(self::$serializer[$ser], $ser) : $ser; + } return $a; } From 870c26f39b757f8c5c6d332e4aa53a74b722bcbd Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 10 Mar 2017 23:26:11 +0100 Subject: [PATCH 06/88] [VarDumper] Add missing isset() checks in some casters --- .../VarDumper/Caster/ExceptionCaster.php | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php index 25635399f7bd7..b4fc87a275e25 100644 --- a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php @@ -67,11 +67,13 @@ public static function castThrowingCasterException(ThrowingCasterException $e, a if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace'])) { $b = (array) $a[$xPrefix.'previous']; - array_unshift($b[$xPrefix.'trace'], array( - 'function' => 'new '.get_class($a[$xPrefix.'previous']), - 'file' => $b[$prefix.'file'], - 'line' => $b[$prefix.'line'], - )); + if (isset($a[$prefix.'file'], $a[$prefix.'line'])) { + array_unshift($b[$xPrefix.'trace'], array( + 'function' => 'new '.get_class($a[$xPrefix.'previous']), + 'file' => $b[$prefix.'file'], + 'line' => $b[$prefix.'line'], + )); + } $a[$xPrefix.'trace'] = new TraceStub($b[$xPrefix.'trace'], false, 0, -1 - count($a[$xPrefix.'trace']->value)); } @@ -234,11 +236,13 @@ private static function filterExceptionArray($xClass, array $a, $xPrefix, $filte } if (!($filter & Caster::EXCLUDE_VERBOSE)) { - array_unshift($trace, array( - 'function' => $xClass ? 'new '.$xClass : null, - 'file' => $a[Caster::PREFIX_PROTECTED.'file'], - 'line' => $a[Caster::PREFIX_PROTECTED.'line'], - )); + if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { + array_unshift($trace, array( + 'function' => $xClass ? 'new '.$xClass : null, + 'file' => $a[Caster::PREFIX_PROTECTED.'file'], + 'line' => $a[Caster::PREFIX_PROTECTED.'line'], + )); + } $a[$xPrefix.'trace'] = new TraceStub($trace, self::$traceArgs); } if (empty($a[$xPrefix.'previous'])) { From 6831b984e114333bdee74357a293c89e1e279c28 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 12 Mar 2017 17:00:52 +0100 Subject: [PATCH 07/88] [VarDumper] ExceptionCaster robustness fix --- src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php index 8452590d63dad..b6c0c28f50eb7 100644 --- a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php @@ -64,7 +64,7 @@ public static function castThrowingCasterException(ThrowingCasterException $e, a $prefix = Caster::PREFIX_PROTECTED; $xPrefix = "\0Exception\0"; - if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace'][0])) { + if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace'][0]) && $a[$xPrefix.'previous'] instanceof \Exception) { $b = (array) $a[$xPrefix.'previous']; $b[$xPrefix.'trace'][0] += array( 'file' => $b[$prefix.'file'], From 33946e69c0a322fa1aa721aed26488bf2c5098c8 Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Sun, 12 Mar 2017 23:37:52 +0100 Subject: [PATCH 08/88] Use proper line endings --- src/Symfony/Component/Console/Output/BufferedOutput.php | 2 +- src/Symfony/Component/Console/Tests/Fixtures/DummyOutput.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Output/BufferedOutput.php b/src/Symfony/Component/Console/Output/BufferedOutput.php index 5682fc2404f78..205b02f5fd5d1 100644 --- a/src/Symfony/Component/Console/Output/BufferedOutput.php +++ b/src/Symfony/Component/Console/Output/BufferedOutput.php @@ -42,7 +42,7 @@ protected function doWrite($message, $newline) $this->buffer .= $message; if ($newline) { - $this->buffer .= "\n"; + $this->buffer .= PHP_EOL; } } } diff --git a/src/Symfony/Component/Console/Tests/Fixtures/DummyOutput.php b/src/Symfony/Component/Console/Tests/Fixtures/DummyOutput.php index 0070c0a48676c..866e21437177a 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/DummyOutput.php +++ b/src/Symfony/Component/Console/Tests/Fixtures/DummyOutput.php @@ -26,7 +26,7 @@ class DummyOutput extends BufferedOutput public function getLogs() { $logs = array(); - foreach (explode("\n", trim($this->fetch())) as $message) { + foreach (explode(PHP_EOL, trim($this->fetch())) as $message) { preg_match('/^\[(.*)\] (.*)/', $message, $matches); $logs[] = sprintf('%s %s', $matches[1], $matches[2]); } From 4842c86324a64d12a903dd2d712977eb132b2718 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 10 Mar 2017 23:00:00 +0100 Subject: [PATCH 09/88] [FrameworkBundle] Fix cleaning of test dirs --- .../Tests/Functional/SessionTest.php | 14 ----------- .../Tests/Functional/WebTestCase.php | 23 +++++++++++++++---- .../Tests/Functional/app/AppKernel.php | 12 ++++++---- .../Tests/Functional/CsrfFormLoginTest.php | 10 -------- .../Functional/FirewallEntryPointTest.php | 10 -------- .../Tests/Functional/FormLoginTest.php | 10 -------- .../Functional/LocalizedRoutesAsPathTest.php | 10 -------- .../SecurityRoutingIntegrationTest.php | 10 -------- .../Tests/Functional/SetAclCommandTest.php | 14 ----------- .../Tests/Functional/SwitchUserTest.php | 10 -------- .../Tests/Functional/WebTestCase.php | 23 +++++++++++++++---- .../Tests/Functional/app/AppKernel.php | 14 ++++++----- 12 files changed, 53 insertions(+), 107 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php index 415e031189c3a..166d8a33919df 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php @@ -134,18 +134,4 @@ public function getConfigs() array('config.yml', false), ); } - - protected function setUp() - { - parent::setUp(); - - $this->deleteTmpDir('SessionTest'); - } - - protected function tearDown() - { - parent::tearDown(); - - $this->deleteTmpDir('SessionTest'); - } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/WebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/WebTestCase.php index 50d4cfa4db269..2861297fe0256 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/WebTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/WebTestCase.php @@ -13,7 +13,6 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\HttpKernel\Kernel; class WebTestCase extends BaseWebTestCase { @@ -23,9 +22,19 @@ public static function assertRedirect($response, $location) self::assertEquals('http://localhost'.$location, $response->headers->get('Location')); } - protected function deleteTmpDir($testCase) + public static function setUpBeforeClass() { - if (!file_exists($dir = sys_get_temp_dir().'/'.Kernel::VERSION.'/'.$testCase)) { + static::deleteTmpDir(); + } + + public static function tearDownAfterClass() + { + static::deleteTmpDir(); + } + + protected static function deleteTmpDir() + { + if (!file_exists($dir = sys_get_temp_dir().'/'.static::getVarDir())) { return; } @@ -49,10 +58,16 @@ protected static function createKernel(array $options = array()) } return new $class( + static::getVarDir(), $options['test_case'], isset($options['root_config']) ? $options['root_config'] : 'config.yml', - isset($options['environment']) ? $options['environment'] : 'frameworkbundletest'.strtolower($options['test_case']), + isset($options['environment']) ? $options['environment'] : strtolower(static::getVarDir().$options['test_case']), isset($options['debug']) ? $options['debug'] : true ); } + + protected static function getVarDir() + { + return substr(strrchr(get_called_class(), '\\'), 1); + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php index b07d44fe22be5..8e14b53a7472d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php @@ -46,14 +46,16 @@ */ class AppKernel extends Kernel { + private $varDir; private $testCase; private $rootConfig; - public function __construct($testCase, $rootConfig, $environment, $debug) + public function __construct($varDir, $testCase, $rootConfig, $environment, $debug) { if (!is_dir(__DIR__.'/'.$testCase)) { throw new \InvalidArgumentException(sprintf('The test case "%s" does not exist.', $testCase)); } + $this->varDir = $varDir; $this->testCase = $testCase; $fs = new Filesystem(); @@ -81,12 +83,12 @@ public function getRootDir() public function getCacheDir() { - return sys_get_temp_dir().'/'.Kernel::VERSION.'/'.$this->testCase.'/cache/'.$this->environment; + return sys_get_temp_dir().'/'.$this->varDir.'/'.$this->testCase.'/cache/'.$this->environment; } public function getLogDir() { - return sys_get_temp_dir().'/'.Kernel::VERSION.'/'.$this->testCase.'/logs'; + return sys_get_temp_dir().'/'.$this->varDir.'/'.$this->testCase.'/logs'; } public function registerContainerConfiguration(LoaderInterface $loader) @@ -96,13 +98,13 @@ public function registerContainerConfiguration(LoaderInterface $loader) public function serialize() { - return serialize(array($this->testCase, $this->rootConfig, $this->getEnvironment(), $this->isDebug())); + return serialize(array($this->varDir, $this->testCase, $this->rootConfig, $this->getEnvironment(), $this->isDebug())); } public function unserialize($str) { $a = unserialize($str); - $this->__construct($a[0], $a[1], $a[2], $a[3]); + $this->__construct($a[0], $a[1], $a[2], $a[3], $a[4]); } protected function getKernelParameters() diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php index 80211f5251b08..2d95d35065137 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php @@ -108,14 +108,4 @@ public function getConfigs() array('routes_as_path.yml'), ); } - - public static function setUpBeforeClass() - { - parent::deleteTmpDir('CsrfFormLogin'); - } - - public static function tearDownAfterClass() - { - parent::deleteTmpDir('CsrfFormLogin'); - } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FirewallEntryPointTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FirewallEntryPointTest.php index 30d0935ffddd7..8179c2e942a6c 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FirewallEntryPointTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FirewallEntryPointTest.php @@ -43,14 +43,4 @@ public function testItUsesTheConfiguredEntryPointFromTheExceptionListenerWithFor "Custom entry point wasn't started" ); } - - public static function setUpBeforeClass() - { - parent::deleteTmpDir('FirewallEntryPoint'); - } - - public static function tearDownAfterClass() - { - parent::deleteTmpDir('FirewallEntryPoint'); - } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php index 2f19f3f8a1a9a..c2e766e9acca1 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php @@ -113,14 +113,4 @@ public function getConfigs() array('routes_as_path.yml'), ); } - - public static function setUpBeforeClass() - { - parent::deleteTmpDir('StandardFormLogin'); - } - - public static function tearDownAfterClass() - { - parent::deleteTmpDir('StandardFormLogin'); - } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php index 14c317966e21a..cb600764eaf42 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php @@ -76,14 +76,4 @@ public function getLocales() { return array(array('en'), array('de')); } - - public static function setUpBeforeClass() - { - parent::deleteTmpDir('StandardFormLogin'); - } - - public static function tearDownAfterClass() - { - parent::deleteTmpDir('StandardFormLogin'); - } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php index c7db437819a1c..3abfd9585f159 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php @@ -116,14 +116,4 @@ public function getConfigs() { return array(array('config.yml'), array('routes_as_path.yml')); } - - public static function setUpBeforeClass() - { - parent::deleteTmpDir('StandardFormLogin'); - } - - public static function tearDownAfterClass() - { - parent::deleteTmpDir('StandardFormLogin'); - } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SetAclCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SetAclCommandTest.php index db4c51c5f064d..039a5b325bad6 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SetAclCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SetAclCommandTest.php @@ -40,20 +40,6 @@ class SetAclCommandTest extends WebTestCase const OBJECT_CLASS = 'Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AclBundle\Entity\Car'; const SECURITY_CLASS = 'Symfony\Component\Security\Core\User\User'; - protected function setUp() - { - parent::setUp(); - - $this->deleteTmpDir('Acl'); - } - - protected function tearDown() - { - parent::tearDown(); - - $this->deleteTmpDir('Acl'); - } - public function testSetAclUser() { $objectId = 1; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php index e5079c3283aac..f12e95671be2c 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php @@ -70,14 +70,4 @@ protected function createAuthenticatedClient($username) return $client; } - - public static function setUpBeforeClass() - { - parent::deleteTmpDir('StandardFormLogin'); - } - - public static function tearDownAfterClass() - { - parent::deleteTmpDir('StandardFormLogin'); - } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php index da07116ae0665..8bace799a37a8 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php @@ -13,7 +13,6 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\HttpKernel\Kernel; class WebTestCase extends BaseWebTestCase { @@ -23,9 +22,19 @@ public static function assertRedirect($response, $location) self::assertEquals('http://localhost'.$location, $response->headers->get('Location')); } - protected static function deleteTmpDir($testCase) + public static function setUpBeforeClass() { - if (defined('HHVM_VERSION_ID') || !file_exists($dir = sys_get_temp_dir().'/'.Kernel::VERSION.'/'.$testCase)) { + static::deleteTmpDir(); + } + + public static function tearDownAfterClass() + { + static::deleteTmpDir(); + } + + protected static function deleteTmpDir() + { + if (!file_exists($dir = sys_get_temp_dir().'/'.static::getVarDir())) { return; } @@ -49,10 +58,16 @@ protected static function createKernel(array $options = array()) } return new $class( + static::getVarDir(), $options['test_case'], isset($options['root_config']) ? $options['root_config'] : 'config.yml', - isset($options['environment']) ? $options['environment'] : 'securitybundletest'.strtolower($options['test_case']), + isset($options['environment']) ? $options['environment'] : strtolower(static::getVarDir().$options['test_case']), isset($options['debug']) ? $options['debug'] : true ); } + + protected static function getVarDir() + { + return substr(strrchr(get_called_class(), '\\'), 1); + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php index b828c5acfd91b..c448b7c172d60 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php @@ -46,14 +46,16 @@ */ class AppKernel extends Kernel { + private $varDir; private $testCase; private $rootConfig; - public function __construct($testCase, $rootConfig, $environment, $debug) + public function __construct($varDir, $testCase, $rootConfig, $environment, $debug) { if (!is_dir(__DIR__.'/'.$testCase)) { throw new \InvalidArgumentException(sprintf('The test case "%s" does not exist.', $testCase)); } + $this->varDir = $varDir; $this->testCase = $testCase; $fs = new Filesystem(); @@ -71,7 +73,7 @@ public function __construct($testCase, $rootConfig, $environment, $debug) public function getName() { if (null === $this->name) { - $this->name = parent::getName().md5($this->rootConfig); + $this->name = parent::getName().substr(md5($this->rootConfig), -16); } return $this->name; @@ -93,12 +95,12 @@ public function getRootDir() public function getCacheDir() { - return sys_get_temp_dir().'/'.Kernel::VERSION.'/'.$this->testCase.'/cache/'.$this->environment; + return sys_get_temp_dir().'/'.$this->varDir.'/'.$this->testCase.'/cache/'.$this->environment; } public function getLogDir() { - return sys_get_temp_dir().'/'.Kernel::VERSION.'/'.$this->testCase.'/logs'; + return sys_get_temp_dir().'/'.$this->varDir.'/'.$this->testCase.'/logs'; } public function registerContainerConfiguration(LoaderInterface $loader) @@ -108,13 +110,13 @@ public function registerContainerConfiguration(LoaderInterface $loader) public function serialize() { - return serialize(array($this->testCase, $this->rootConfig, $this->getEnvironment(), $this->isDebug())); + return serialize(array($this->varDir, $this->testCase, $this->rootConfig, $this->getEnvironment(), $this->isDebug())); } public function unserialize($str) { $a = unserialize($str); - $this->__construct($a[0], $a[1], $a[2], $a[3]); + $this->__construct($a[0], $a[1], $a[2], $a[3], $a[4]); } protected function getKernelParameters() From 86e8afaea0fc3361b7da12d82ce6b62596ca6a2b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 14 Mar 2017 09:04:19 +0100 Subject: [PATCH 10/88] [Validator] revert wrong Phpdoc change --- src/Symfony/Component/Validator/Mapping/ClassMetadata.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php index fe5e6e51e2ec4..f895ad40402dc 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php @@ -299,9 +299,8 @@ public function addPropertyConstraints($property, array $constraints) * The name of the getter is assumed to be the name of the property with an * uppercased first letter and either the prefix "get" or "is". * - * @param string $property The name of the property - * @param Constraint $constraint The constraint - * @param string|null $method The method that is called to retrieve the value being validated (null for auto-detection) + * @param string $property The name of the property + * @param Constraint $constraint The constraint * * @return $this */ From 405bd4cc81effce9fd24b9c81e8383c4b5337c5a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 14 Mar 2017 12:32:10 +0100 Subject: [PATCH 11/88] Use PHP functions as array_map callbacks when possible --- .../Tests/DependencyInjection/FrameworkExtensionTest.php | 2 +- .../Tests/DependencyInjection/CompleteConfigurationTest.php | 2 +- src/Symfony/Component/Finder/Tests/FinderTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index bc1eac93e6dac..a782a3f0748bb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -224,7 +224,7 @@ public function testTranslator() $this->assertEquals('translator.default', (string) $container->getAlias('translator'), '->registerTranslatorConfiguration() redefines translator service from identity to real translator'); $options = $container->getDefinition('translator.default')->getArgument(3); - $files = array_map(function ($resource) { return realpath($resource); }, $options['resource_files']['en']); + $files = array_map('realpath', $options['resource_files']['en']); $ref = new \ReflectionClass('Symfony\Component\Validator\Validation'); $this->assertContains( strtr(dirname($ref->getFileName()).'/Resources/translations/validators.en.xlf', '/', DIRECTORY_SEPARATOR), diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index ebb22fddac833..d273fb05942b3 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -73,7 +73,7 @@ public function testFirewalls() foreach (array_keys($arguments[1]) as $contextId) { $contextDef = $container->getDefinition($contextId); $arguments = $contextDef->getArguments(); - $listeners[] = array_map(function ($ref) { return (string) $ref; }, $arguments['index_0']); + $listeners[] = array_map('strval', $arguments['index_0']); } $this->assertEquals(array( diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index 28bb4dbdbb699..f445c79c5ef2b 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -317,7 +317,7 @@ public function testGetIterator() $finder = $this->buildFinder(); $a = iterator_to_array($finder->directories()->in(self::$tmpDir)); - $a = array_values(array_map(function ($a) { return (string) $a; }, $a)); + $a = array_values(array_map('strval', $a)); sort($a); $this->assertEquals($expected, $a, 'implements the \IteratorAggregate interface'); } From 9d9d4efb88539b32413d6ac51e9639a0295502cc Mon Sep 17 00:00:00 2001 From: David Maicher Date: Tue, 14 Mar 2017 21:52:39 +0100 Subject: [PATCH 12/88] [Doctrine Bridge] fix priority for doctrine event listeners --- ...gisterEventListenersAndSubscribersPass.php | 168 ++++++++++-------- ...erEventListenersAndSubscribersPassTest.php | 156 ++++++++++++---- 2 files changed, 210 insertions(+), 114 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php index 94f72fd8c8c05..1ec3ba323b788 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php @@ -11,27 +11,30 @@ namespace Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; /** * Registers event listeners and subscribers to the available doctrine connections. * * @author Jeremy Mikola * @author Alexander + * @author David Maicher */ class RegisterEventListenersAndSubscribersPass implements CompilerPassInterface { + /** + * @var string|string[] + */ private $connections; - private $container; private $eventManagers; private $managerTemplate; private $tagPrefix; /** - * Constructor. - * * @param string $connections Parameter ID for connections * @param string $managerTemplate sprintf() template for generating the event * manager's service ID for a connection name @@ -53,105 +56,112 @@ public function process(ContainerBuilder $container) return; } - $taggedSubscribers = $container->findTaggedServiceIds($this->tagPrefix.'.event_subscriber'); - $taggedListeners = $container->findTaggedServiceIds($this->tagPrefix.'.event_listener'); - - if (empty($taggedSubscribers) && empty($taggedListeners)) { - return; - } - - $this->container = $container; $this->connections = $container->getParameter($this->connections); - $sortFunc = function ($a, $b) { - $a = isset($a['priority']) ? $a['priority'] : 0; - $b = isset($b['priority']) ? $b['priority'] : 0; - - return $a > $b ? -1 : 1; - }; + $this->addTaggedSubscribers($container); + $this->addTaggedListeners($container); + } - if (!empty($taggedSubscribers)) { - $subscribersPerCon = $this->groupByConnection($taggedSubscribers); - foreach ($subscribersPerCon as $con => $subscribers) { - $em = $this->getEventManager($con); + private function addTaggedSubscribers(ContainerBuilder $container) + { + $subscriberTag = $this->tagPrefix.'.event_subscriber'; + $taggedSubscribers = $this->findAndSortTags($subscriberTag, $container); - uasort($subscribers, $sortFunc); - foreach ($subscribers as $id => $instance) { - if ($container->getDefinition($id)->isAbstract()) { - throw new \InvalidArgumentException(sprintf('The abstract service "%s" cannot be tagged as a doctrine event subscriber.', $id)); - } + foreach ($taggedSubscribers as $taggedSubscriber) { + $id = $taggedSubscriber[0]; + $taggedSubscriberDef = $container->getDefinition($id); - $em->addMethodCall('addEventSubscriber', array(new Reference($id))); - } + if ($taggedSubscriberDef->isAbstract()) { + throw new InvalidArgumentException(sprintf('The abstract service "%s" cannot be tagged as a doctrine event subscriber.', $id)); } - } - if (!empty($taggedListeners)) { - $listenersPerCon = $this->groupByConnection($taggedListeners, true); - foreach ($listenersPerCon as $con => $listeners) { - $em = $this->getEventManager($con); - - uasort($listeners, $sortFunc); - foreach ($listeners as $id => $instance) { - if ($container->getDefinition($id)->isAbstract()) { - throw new \InvalidArgumentException(sprintf('The abstract service "%s" cannot be tagged as a doctrine event listener.', $id)); - } - - $em->addMethodCall('addEventListener', array( - array_unique($instance['event']), - isset($instance['lazy']) && $instance['lazy'] ? $id : new Reference($id), - )); + $tag = $taggedSubscriber[1]; + $connections = isset($tag['connection']) ? array($tag['connection']) : array_keys($this->connections); + foreach ($connections as $con) { + if (!isset($this->connections[$con])) { + throw new RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $taggedSubscriber, implode(', ', array_keys($this->connections)))); } + + $this->getEventManagerDef($container, $con)->addMethodCall('addEventSubscriber', array(new Reference($id))); } } } - private function groupByConnection(array $services, $isListener = false) + private function addTaggedListeners(ContainerBuilder $container) { - $grouped = array(); - foreach ($allCons = array_keys($this->connections) as $con) { - $grouped[$con] = array(); - } + $listenerTag = $this->tagPrefix.'.event_listener'; + $taggedListeners = $this->findAndSortTags($listenerTag, $container); + + foreach ($taggedListeners as $taggedListener) { + $id = $taggedListener[0]; + $taggedListenerDef = $container->getDefinition($taggedListener[0]); + if ($taggedListenerDef->isAbstract()) { + throw new InvalidArgumentException(sprintf('The abstract service "%s" cannot be tagged as a doctrine event listener.', $id)); + } - foreach ($services as $id => $instances) { - foreach ($instances as $instance) { - if ($isListener) { - if (!isset($instance['event'])) { - throw new \InvalidArgumentException(sprintf('Doctrine event listener "%s" must specify the "event" attribute.', $id)); - } - $instance['event'] = array($instance['event']); - - if (isset($instance['lazy']) && $instance['lazy']) { - $this->container->getDefinition($id)->setPublic(true); - } + $tag = $taggedListener[1]; + if (!isset($tag['event'])) { + throw new InvalidArgumentException(sprintf('Doctrine event listener "%s" must specify the "event" attribute.', $id)); + } + + $connections = isset($tag['connection']) ? array($tag['connection']) : array_keys($this->connections); + foreach ($connections as $con) { + if (!isset($this->connections[$con])) { + throw new RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $id, implode(', ', array_keys($this->connections)))); } - $cons = isset($instance['connection']) ? array($instance['connection']) : $allCons; - foreach ($cons as $con) { - if (!isset($grouped[$con])) { - throw new \RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $id, implode(', ', array_keys($this->connections)))); - } - - if ($isListener && isset($grouped[$con][$id])) { - $grouped[$con][$id]['event'] = array_merge($grouped[$con][$id]['event'], $instance['event']); - } else { - $grouped[$con][$id] = $instance; - } + if ($lazy = isset($tag['lazy']) && $tag['lazy']) { + $taggedListenerDef->setPublic(true); } + + // we add one call per event per service so we have the correct order + $this->getEventManagerDef($container, $con)->addMethodCall('addEventListener', array( + $tag['event'], + $lazy ? $id : new Reference($id), + )); } } + } - return $grouped; + private function getEventManagerDef(ContainerBuilder $container, $name) + { + if (!isset($this->eventManagers[$name])) { + $this->eventManagers[$name] = $container->getDefinition(sprintf($this->managerTemplate, $name)); + } + + return $this->eventManagers[$name]; } - private function getEventManager($name) + /** + * Finds and orders all service tags with the given name by their priority. + * + * The order of additions must be respected for services having the same priority, + * and knowing that the \SplPriorityQueue class does not respect the FIFO method, + * we should not use this class. + * + * @see https://bugs.php.net/bug.php?id=53710 + * @see https://bugs.php.net/bug.php?id=60926 + * + * @param string $tagName + * @param ContainerBuilder $container + * + * @return array + */ + private function findAndSortTags($tagName, ContainerBuilder $container) { - if (null === $this->eventManagers) { - $this->eventManagers = array(); - foreach ($this->connections as $n => $id) { - $this->eventManagers[$n] = $this->container->getDefinition(sprintf($this->managerTemplate, $n)); + $sortedTags = array(); + + foreach ($container->findTaggedServiceIds($tagName) as $serviceId => $tags) { + foreach ($tags as $attributes) { + $priority = isset($attributes['priority']) ? $attributes['priority'] : 0; + $sortedTags[$priority][] = array($serviceId, $attributes); } } - return $this->eventManagers[$name]; + if ($sortedTags) { + krsort($sortedTags); + $sortedTags = call_user_func_array('array_merge', $sortedTags); + } + + return $sortedTags; } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPassTest.php b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPassTest.php index ba73678541e7e..4f196f2ca6a24 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPassTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPassTest.php @@ -14,6 +14,7 @@ use Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterEventListenersAndSubscribersPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; class RegisterEventListenersAndSubscribersPassTest extends \PHPUnit_Framework_TestCase { @@ -55,12 +56,18 @@ public function testProcessEventListenersWithPriorities() $container ->register('a', 'stdClass') + ->setPublic(false) + ->addTag('doctrine.event_listener', array( + 'event' => 'bar', + )) ->addTag('doctrine.event_listener', array( 'event' => 'foo', 'priority' => -5, )) ->addTag('doctrine.event_listener', array( - 'event' => 'bar', + 'event' => 'foo_bar', + 'priority' => 3, + 'lazy' => true, )) ; $container @@ -69,12 +76,34 @@ public function testProcessEventListenersWithPriorities() 'event' => 'foo', )) ; + $container + ->register('c', 'stdClass') + ->addTag('doctrine.event_listener', array( + 'event' => 'foo_bar', + 'priority' => 4, + )) + ; $this->process($container); - $this->assertEquals(array('b', 'a'), $this->getServiceOrder($container, 'addEventListener')); - - $calls = $container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls(); - $this->assertEquals(array('foo', 'bar'), $calls[1][1][0]); + $methodCalls = $container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls(); + + $this->assertEquals( + array( + array('addEventListener', array('foo_bar', new Reference('c'))), + array('addEventListener', array('foo_bar', new Reference('a'))), + array('addEventListener', array('bar', new Reference('a'))), + array('addEventListener', array('foo', new Reference('b'))), + array('addEventListener', array('foo', new Reference('a'))), + ), + $methodCalls + ); + + // not lazy so must be reference + $this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $methodCalls[0][1][1]); + + // lazy so id instead of reference and must mark service public + $this->assertSame('a', $methodCalls[1][1][1]); + $this->assertTrue($container->getDefinition('a')->isPublic()); } public function testProcessEventListenersWithMultipleConnections() @@ -87,15 +116,86 @@ public function testProcessEventListenersWithMultipleConnections() 'event' => 'onFlush', )) ; + + $container + ->register('b', 'stdClass') + ->addTag('doctrine.event_listener', array( + 'event' => 'onFlush', + 'connection' => 'default', + )) + ; + + $container + ->register('c', 'stdClass') + ->addTag('doctrine.event_listener', array( + 'event' => 'onFlush', + 'connection' => 'second', + )) + ; + $this->process($container); - $callsDefault = $container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls(); + $this->assertEquals( + array( + array('addEventListener', array('onFlush', new Reference('a'))), + array('addEventListener', array('onFlush', new Reference('b'))), + ), + $container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls() + ); + + $this->assertEquals( + array( + array('addEventListener', array('onFlush', new Reference('a'))), + array('addEventListener', array('onFlush', new Reference('c'))), + ), + $container->getDefinition('doctrine.dbal.second_connection.event_manager')->getMethodCalls() + ); + } - $this->assertEquals('addEventListener', $callsDefault[0][0]); - $this->assertEquals(array('onFlush'), $callsDefault[0][1][0]); + public function testProcessEventSubscribersWithMultipleConnections() + { + $container = $this->createBuilder(true); - $callsSecond = $container->getDefinition('doctrine.dbal.second_connection.event_manager')->getMethodCalls(); - $this->assertEquals($callsDefault, $callsSecond); + $container + ->register('a', 'stdClass') + ->addTag('doctrine.event_subscriber', array( + 'event' => 'onFlush', + )) + ; + + $container + ->register('b', 'stdClass') + ->addTag('doctrine.event_subscriber', array( + 'event' => 'onFlush', + 'connection' => 'default', + )) + ; + + $container + ->register('c', 'stdClass') + ->addTag('doctrine.event_subscriber', array( + 'event' => 'onFlush', + 'connection' => 'second', + )) + ; + + $this->process($container); + + $this->assertEquals( + array( + array('addEventSubscriber', array(new Reference('a'))), + array('addEventSubscriber', array(new Reference('b'))), + ), + $container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls() + ); + + $this->assertEquals( + array( + array('addEventSubscriber', array(new Reference('a'))), + array('addEventSubscriber', array(new Reference('c'))), + ), + $container->getDefinition('doctrine.dbal.second_connection.event_manager')->getMethodCalls() + ); } public function testProcessEventSubscribersWithPriorities() @@ -132,11 +232,17 @@ public function testProcessEventSubscribersWithPriorities() ; $this->process($container); - $serviceOrder = $this->getServiceOrder($container, 'addEventSubscriber'); - $unordered = array_splice($serviceOrder, 0, 3); - sort($unordered); - $this->assertEquals(array('c', 'd', 'e'), $unordered); - $this->assertEquals(array('b', 'a'), $serviceOrder); + + $this->assertEquals( + array( + array('addEventSubscriber', array(new Reference('c'))), + array('addEventSubscriber', array(new Reference('d'))), + array('addEventSubscriber', array(new Reference('e'))), + array('addEventSubscriber', array(new Reference('b'))), + array('addEventSubscriber', array(new Reference('a'))), + ), + $container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls() + ); } public function testProcessNoTaggedServices() @@ -156,26 +262,6 @@ private function process(ContainerBuilder $container) $pass->process($container); } - private function getServiceOrder(ContainerBuilder $container, $method) - { - $order = array(); - foreach ($container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls() as $call) { - list($name, $arguments) = $call; - if ($method !== $name) { - continue; - } - - if ('addEventListener' === $name) { - $order[] = (string) $arguments[1]; - continue; - } - - $order[] = (string) $arguments[0]; - } - - return $order; - } - private function createBuilder($multipleConnections = false) { $container = new ContainerBuilder(); From ebb316d616a0a1a0818475270892e03197647d03 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 14 Mar 2017 13:26:05 +0100 Subject: [PATCH 13/88] [Cache] Enhance error reporting for FilesystemAdapter --- .../Cache/Adapter/FilesystemAdapterTrait.php | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemAdapterTrait.php b/src/Symfony/Component/Cache/Adapter/FilesystemAdapterTrait.php index 156fc5c1fb63a..d406c062c5908 100644 --- a/src/Symfony/Component/Cache/Adapter/FilesystemAdapterTrait.php +++ b/src/Symfony/Component/Cache/Adapter/FilesystemAdapterTrait.php @@ -47,7 +47,6 @@ private function init($namespace, $directory) } $this->directory = $dir; - $this->tmp = $this->directory.uniqid('', true); } /** @@ -81,19 +80,21 @@ protected function doDelete(array $ids) private function write($file, $data, $expiresAt = null) { - if (false === @file_put_contents($this->tmp, $data)) { - return false; - } - if (null !== $expiresAt) { - @touch($this->tmp, $expiresAt); - } + set_error_handler(__CLASS__.'::throwError'); + try { + if (null === $this->tmp) { + $this->tmp = $this->directory.uniqid('', true); + } + file_put_contents($this->tmp, $data); - if (@rename($this->tmp, $file)) { - return true; - } - @unlink($this->tmp); + if (null !== $expiresAt) { + touch($this->tmp, $expiresAt); + } - return false; + return rename($this->tmp, $file); + } finally { + restore_error_handler(); + } } private function getFile($id, $mkdir = false) @@ -107,4 +108,20 @@ private function getFile($id, $mkdir = false) return $dir.substr($hash, 2, 20); } + + /** + * @internal + */ + public static function throwError($type, $message, $file, $line) + { + throw new \ErrorException($message, 0, $type, $file, $line); + } + + public function __destruct() + { + parent::__destruct(); + if (null !== $this->tmp && file_exists($this->tmp)) { + unlink($this->tmp); + } + } } From 522ec3ef0c71707a98c46e0ae7d56d8fb0f88427 Mon Sep 17 00:00:00 2001 From: Dmytro Boiko Date: Thu, 16 Mar 2017 00:00:25 +0200 Subject: [PATCH 14/88] [Security] Added option to return true in the method isRememberMeRequested --- .../Security/Http/RememberMe/AbstractRememberMeServices.php | 2 +- .../Http/Tests/RememberMe/AbstractRememberMeServicesTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php index cd8640d03a13e..4ab3465c66263 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php @@ -318,6 +318,6 @@ protected function isRememberMeRequested(Request $request) $this->logger->debug('Did not send remember-me cookie.', array('parameter' => $this->options['remember_me_parameter'])); } - return $parameter === 'true' || $parameter === 'on' || $parameter === '1' || $parameter === 'yes'; + return $parameter === 'true' || $parameter === 'on' || $parameter === '1' || $parameter === 'yes' || $parameter === true; } } diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php index 386927e3d50b9..1850d093dd4f6 100644 --- a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php +++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php @@ -251,6 +251,7 @@ public function getPositiveRememberMeParameterValues() array('1'), array('on'), array('yes'), + array(true), ); } From e47cfe903e629cc2bc18cd649b927bc743110919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 16 Mar 2017 10:52:38 +0100 Subject: [PATCH 15/88] [Workflow] Added more tests --- .../Component/Workflow/Tests/WorkflowTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index ab8c767b59c17..c1efb0182765a 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -104,6 +104,23 @@ public function testCan() $this->assertTrue($workflow->can($subject, 't1')); $this->assertFalse($workflow->can($subject, 't2')); + + $subject->marking = array('b' => 1); + + $this->assertFalse($workflow->can($subject, 't1')); + // In a workflow net, all "from" places should contain a token to enable + // the transition. + $this->assertFalse($workflow->can($subject, 't2')); + + $subject->marking = array('b' => 1, 'c' => 1); + + $this->assertFalse($workflow->can($subject, 't1')); + $this->assertTrue($workflow->can($subject, 't2')); + + $subject->marking = array('f' => 1); + + $this->assertFalse($workflow->can($subject, 't5')); + $this->assertTrue($workflow->can($subject, 't6')); } public function testCanWithGuard() From 5af47c40dc6767f19185f1340037bc1c65e724c5 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 16 Mar 2017 17:10:10 +0100 Subject: [PATCH 16/88] Revert "bug #21841 [Console] Do not squash input changes made from console.command event (chalasr)" This reverts commit b8b6774634512e66b45e33f5f598cf14865701e4, reversing changes made to 82790559de7b53b1e11814a964733ccb68a736d1. --- src/Symfony/Component/Console/Application.php | 4 --- .../Component/Console/Command/Command.php | 21 ++++------------ .../Console/Tests/ApplicationTest.php | 25 ------------------- 3 files changed, 5 insertions(+), 45 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index d069da03bc06a..bd340d3078f7f 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -859,10 +859,6 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition } - // don't bind the input again as it would override any input argument/option set from the command event in - // addition to being useless - $command->setInputBound(true); - $event = new ConsoleCommandEvent($command, $input, $output); $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event); diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index fd0376c22d029..39a1f6e8444bc 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -42,7 +42,6 @@ class Command private $ignoreValidationErrors = false; private $applicationDefinitionMerged = false; private $applicationDefinitionMergedWithArgs = false; - private $inputBound = false; private $code; private $synopsis = array(); private $usages = array(); @@ -219,13 +218,11 @@ public function run(InputInterface $input, OutputInterface $output) $this->mergeApplicationDefinition(); // bind the input against the command specific arguments/options - if (!$this->inputBound) { - try { - $input->bind($this->definition); - } catch (ExceptionInterface $e) { - if (!$this->ignoreValidationErrors) { - throw $e; - } + try { + $input->bind($this->definition); + } catch (ExceptionInterface $e) { + if (!$this->ignoreValidationErrors) { + throw $e; } } @@ -681,14 +678,6 @@ public function asXml($asDom = false) return $output->fetch(); } - /** - * @internal - */ - public function setInputBound($inputBound) - { - $this->inputBound = $inputBound; - } - /** * Validates a command name. * diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 3cec084e69734..cd52617a5ac53 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -1113,31 +1113,6 @@ public function testRunWithDispatcherAddingInputOptions() $this->assertEquals('some test value', $extraValue); } - public function testUpdateInputFromConsoleCommandEvent() - { - $dispatcher = $this->getDispatcher(); - $dispatcher->addListener('console.command', function (ConsoleCommandEvent $event) { - $event->getInput()->setOption('extra', 'overriden'); - }); - - $application = new Application(); - $application->setDispatcher($dispatcher); - $application->setAutoExit(false); - - $application - ->register('foo') - ->addOption('extra', null, InputOption::VALUE_REQUIRED) - ->setCode(function (InputInterface $input, OutputInterface $output) { - $output->write('foo.'); - }) - ; - - $tester = new ApplicationTester($application); - $tester->run(array('command' => 'foo', '--extra' => 'original')); - - $this->assertEquals('overriden', $tester->getInput()->getOption('extra')); - } - public function testTerminalDimensions() { $application = new Application(); From e1caf7da7f73fcfcfa3243d0edefc27b813b71e7 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 17 Mar 2017 09:56:29 +0100 Subject: [PATCH 17/88] =?UTF-8?q?[FrameworkBundle]=C2=A0Fix=20translation?= =?UTF-8?q?=20dep=20constraint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Tests/Translation/TranslatorTest.php | 11 +++++++++++ src/Symfony/Bundle/FrameworkBundle/composer.json | 5 +++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php index 1ac206185589c..d9efdfe6e94d5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php @@ -136,6 +136,17 @@ public function testGetDefaultLocale() $this->assertSame('en', $translator->getLocale()); } + /** + * @expectedException \Symfony\Component\Translation\Exception\InvalidArgumentException + * @expectedExceptionMessage The Translator does not support the following options: 'foo' + */ + public function testInvalidOptions() + { + $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock(); + + (new Translator($container, new MessageSelector(), array(), array('foo' => 'bar'))); + } + protected function getCatalogue($locale, $messages, $resources = array()) { $catalogue = new MessageCatalogue($locale); diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 5daeec7e4e76d..965bda053cfb8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -47,7 +47,7 @@ "symfony/security-core": "~3.2", "symfony/security-csrf": "~2.8|~3.0", "symfony/serializer": "~2.8|~3.0", - "symfony/translation": "~2.8|~3.0", + "symfony/translation": "~3.2", "symfony/templating": "~2.8|~3.0", "symfony/validator": "~3.2", "symfony/yaml": "~3.2", @@ -60,7 +60,8 @@ "conflict": { "phpdocumentor/reflection-docblock": "<3.0", "phpdocumentor/type-resolver": "<0.2.0", - "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/translations": "<3.2" }, "suggest": { "ext-apcu": "For best performance of the system caches", From 2e2d018dd8a1e602f2fcdbf04a4fc5c0ebf2c086 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 17 Mar 2017 13:59:59 +0100 Subject: [PATCH 18/88] [Cache] cache/integration-tests is now compatible with phpunit namespaces --- .../Cache/Tests/Adapter/AdapterTestCase.php | 12 ------------ .../Cache/Tests/Adapter/PredisClusterAdapterTest.php | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index 65a040ec7ca65..c3cbd3bef7e54 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -13,18 +13,6 @@ use Cache\IntegrationTests\CachePoolTest; -if (!class_exists('PHPUnit_Framework_TestCase')) { - abstract class AdapterTestCase - { - public static function setUpBeforeClass() - { - self::markTestSkipped('cache/integration-tests is not yet compatible with namespaced phpunit versions.'); - } - } - - return; -} - abstract class AdapterTestCase extends CachePoolTest { protected function setUp() diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisClusterAdapterTest.php index 89a98e4db40a5..6ed1c7d6a9f3b 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PredisClusterAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisClusterAdapterTest.php @@ -16,7 +16,7 @@ class PredisClusterAdapterTest extends AbstractRedisAdapterTest public static function setupBeforeClass() { parent::setupBeforeClass(); - self::$redis = new \Predis\Client(array(getenv('REDIS_HOST'))); + self::$redis = new \Predis\Client(array(array('host' => getenv('REDIS_HOST')))); } public static function tearDownAfterClass() From 46c12c9d1df30fef0fc9bb15eed1f36b07371f8d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 17 Mar 2017 15:04:44 +0100 Subject: [PATCH 19/88] improve message when workflows are missing --- .../DependencyInjection/FrameworkExtension.php | 4 ++++ src/Symfony/Bundle/FrameworkBundle/composer.json | 1 + 2 files changed, 5 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 601e120885fd9..277f0dc62ada5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -397,6 +397,10 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde return; } + if (!class_exists(Workflow\Workflow::class)) { + throw new LogicException('Workflow support cannot be enabled as the Workflow component is not installed.'); + } + $loader->load('workflow.xml'); $registryDefinition = $container->getDefinition('workflow.registry'); diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 965bda053cfb8..fd7c033d69b5b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -50,6 +50,7 @@ "symfony/translation": "~3.2", "symfony/templating": "~2.8|~3.0", "symfony/validator": "~3.2", + "symfony/workflow": "~3.2", "symfony/yaml": "~3.2", "symfony/property-info": "~3.1", "doctrine/annotations": "~1.0", From 71e93dddf2ec1c1921700fd36f03df59f233c788 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 17 Mar 2017 15:28:59 +0100 Subject: [PATCH 20/88] fix package name in conflict rule --- src/Symfony/Bundle/FrameworkBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 965bda053cfb8..9d3c0c126cfaf 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -61,7 +61,7 @@ "phpdocumentor/reflection-docblock": "<3.0", "phpdocumentor/type-resolver": "<0.2.0", "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", - "symfony/translations": "<3.2" + "symfony/translation": "<3.2" }, "suggest": { "ext-apcu": "For best performance of the system caches", From 916a97c834755d67622a00ad01dcd8c5ad4764af Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 17 Mar 2017 16:32:08 +0100 Subject: [PATCH 21/88] [Workflow] add Phpdoc for better IDE support Allow IDEs to provide more precise auto-completion support. --- src/Symfony/Component/Workflow/DefinitionBuilder.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Symfony/Component/Workflow/DefinitionBuilder.php b/src/Symfony/Component/Workflow/DefinitionBuilder.php index 34d27aa5e9d0d..47980004cdec7 100644 --- a/src/Symfony/Component/Workflow/DefinitionBuilder.php +++ b/src/Symfony/Component/Workflow/DefinitionBuilder.php @@ -54,11 +54,17 @@ public function reset() $this->initialPlace = null; } + /** + * @param string $place + */ public function setInitialPlace($place) { $this->initialPlace = $place; } + /** + * @param string $place + */ public function addPlace($place) { if (!preg_match('{^[\w\d_-]+$}', $place)) { @@ -72,6 +78,9 @@ public function addPlace($place) $this->places[$place] = $place; } + /** + * @param string[] $places + */ public function addPlaces(array $places) { foreach ($places as $place) { From c9a1c091829e5791c743ee2ec05f8272fd95bfed Mon Sep 17 00:00:00 2001 From: Richard Bradley Date: Fri, 3 Feb 2017 16:27:28 +0000 Subject: [PATCH 22/88] #20411 fix Yaml parsing for very long quoted strings --- src/Symfony/Component/Yaml/Inline.php | 16 ++-- src/Symfony/Component/Yaml/Parser.php | 88 ++++++++++++------- .../Component/Yaml/Tests/ParserTest.php | 12 +++ 3 files changed, 77 insertions(+), 39 deletions(-) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index aa1833745a95b..2255379a974c6 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -149,8 +149,8 @@ public static function dump($value, $exceptionOnInvalidType = false, $objectSupp case Escaper::requiresDoubleQuoting($value): return Escaper::escapeWithDoubleQuotes($value); case Escaper::requiresSingleQuoting($value): - case preg_match(self::getHexRegex(), $value): - case preg_match(self::getTimestampRegex(), $value): + case Parser::preg_match(self::getHexRegex(), $value): + case Parser::preg_match(self::getTimestampRegex(), $value): return Escaper::escapeWithSingleQuotes($value); default: return $value; @@ -242,10 +242,10 @@ public static function parseScalar($scalar, $delimiters = null, $stringDelimiter $i += strlen($output); // remove comments - if (preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) { + if (Parser::preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) { $output = substr($output, 0, $match[0][1]); } - } elseif (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) { + } elseif (Parser::preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) { $output = $match[1]; $i += strlen($output); } else { @@ -272,7 +272,7 @@ public static function parseScalar($scalar, $delimiters = null, $stringDelimiter */ private static function parseQuotedScalar($scalar, &$i) { - if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) { + if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) { throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i))); } @@ -520,16 +520,16 @@ private static function evaluateScalar($scalar, $references = array()) return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw); case is_numeric($scalar): - case preg_match(self::getHexRegex(), $scalar): + case Parser::preg_match(self::getHexRegex(), $scalar): return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar; case '.inf' === $scalarLower: case '.nan' === $scalarLower: return -log(0); case '-.inf' === $scalarLower: return log(0); - case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar): + case Parser::preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar): return (float) str_replace(',', '', $scalar); - case preg_match(self::getTimestampRegex(), $scalar): + case Parser::preg_match(self::getTimestampRegex(), $scalar): $timeZone = date_default_timezone_get(); date_default_timezone_set('UTC'); $time = strtotime($scalar); diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index f3528ba24fae6..c4f5144468fac 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -61,7 +61,7 @@ public function __construct($offset = 0, $totalNumberOfLines = null, array $skip */ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false) { - if (!preg_match('//u', $value)) { + if (false === preg_match('//u', $value)) { throw new ParseException('The YAML value does not appear to be valid UTF-8.'); } $this->currentLineNb = -1; @@ -92,13 +92,13 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = } $isRef = $mergeNode = false; - if (preg_match('#^\-((?P\s+)(?P.+?))?\s*$#u', $this->currentLine, $values)) { + if (self::preg_match('#^\-((?P\s+)(?P.+))?$#u', rtrim($this->currentLine), $values)) { if ($context && 'mapping' == $context) { throw new ParseException('You cannot define a sequence item when in a mapping', $this->getRealCurrentLineNb() + 1, $this->currentLine); } $context = 'sequence'; - if (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#u', $values['value'], $matches)) { + if (isset($values['value']) && self::preg_match('#^&(?P[^ ]+) *(?P.*)#u', $values['value'], $matches)) { $isRef = $matches['ref']; $values['value'] = $matches['value']; } @@ -108,7 +108,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = $data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $exceptionOnInvalidType, $objectSupport, $objectForMap); } else { if (isset($values['leadspaces']) - && preg_match('#^(?P'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P.+?))?\s*$#u', $values['value'], $matches) + && self::preg_match('#^(?P'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P.+))?$#u', rtrim($values['value']), $matches) ) { // this is a compact notation element, add to next block and parse $block = $values['value']; @@ -124,7 +124,10 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = if ($isRef) { $this->refs[$isRef] = end($data); } - } elseif (preg_match('#^(?P'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{].*?) *\:(\s+(?P.+?))?\s*$#u', $this->currentLine, $values) && (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'")))) { + } elseif ( + self::preg_match('#^(?P'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{].*?) *\:(\s+(?P.+))?$#u', rtrim($this->currentLine), $values) + && (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'"))) + ) { if ($context && 'sequence' == $context) { throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine); } @@ -203,7 +206,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = } } } - } elseif (isset($values['value']) && preg_match('#^&(?P[^ ]+) *(?P.*)#u', $values['value'], $matches)) { + } elseif (isset($values['value']) && self::preg_match('#^&(?P[^ ]+) *(?P.*)#u', $values['value'], $matches)) { $isRef = $matches['ref']; $values['value'] = $matches['value']; } @@ -266,27 +269,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = return $value; } - switch (preg_last_error()) { - case PREG_INTERNAL_ERROR: - $error = 'Internal PCRE error.'; - break; - case PREG_BACKTRACK_LIMIT_ERROR: - $error = 'pcre.backtrack_limit reached.'; - break; - case PREG_RECURSION_LIMIT_ERROR: - $error = 'pcre.recursion_limit reached.'; - break; - case PREG_BAD_UTF8_ERROR: - $error = 'Malformed UTF-8 data.'; - break; - case PREG_BAD_UTF8_OFFSET_ERROR: - $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point.'; - break; - default: - $error = 'Unable to parse.'; - } - - throw new ParseException($error, $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException('Unable to parse', $this->getRealCurrentLineNb() + 1, $this->currentLine); } } @@ -520,7 +503,7 @@ private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $ob return $this->refs[$value]; } - if (preg_match('/^'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) { + if (self::preg_match('/^'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) { $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : ''; return $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers)); @@ -566,7 +549,7 @@ private function parseBlockScalar($style, $chomping = '', $indentation = 0) // determine indentation if not specified if (0 === $indentation) { - if (preg_match('/^ +/', $this->currentLine, $matches)) { + if (self::preg_match('/^ +/', $this->currentLine, $matches)) { $indentation = strlen($matches[0]); } } @@ -577,7 +560,7 @@ private function parseBlockScalar($style, $chomping = '', $indentation = 0) while ( $notEOF && ( $isCurrentLineBlank || - preg_match($pattern, $this->currentLine, $matches) + self::preg_match($pattern, $this->currentLine, $matches) ) ) { if ($isCurrentLineBlank && strlen($this->currentLine) > $indentation) { @@ -800,6 +783,49 @@ private function isStringUnIndentedCollectionItem() */ private function isBlockScalarHeader() { - return (bool) preg_match('~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~', $this->currentLine); + return (bool) self::preg_match('~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~', $this->currentLine); + } + + /** + * A local wrapper for `preg_match` which will throw a ParseException if there + * is an internal error in the PCRE engine. + * + * This avoids us needing to check for "false" every time PCRE is used + * in the YAML engine + * + * @throws ParseException on a PCRE internal error + * + * @see preg_last_error() + * + * @internal + */ + public static function preg_match($pattern, $subject, &$matches = null, $flags = 0, $offset = 0) + { + $ret = preg_match($pattern, $subject, $matches, $flags, $offset); + if ($ret === false) { + switch (preg_last_error()) { + case PREG_INTERNAL_ERROR: + $error = 'Internal PCRE error.'; + break; + case PREG_BACKTRACK_LIMIT_ERROR: + $error = 'pcre.backtrack_limit reached.'; + break; + case PREG_RECURSION_LIMIT_ERROR: + $error = 'pcre.recursion_limit reached.'; + break; + case PREG_BAD_UTF8_ERROR: + $error = 'Malformed UTF-8 data.'; + break; + case PREG_BAD_UTF8_OFFSET_ERROR: + $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point.'; + break; + default: + $error = 'Error.'; + } + + throw new ParseException($error); + } + + return $ret; } } diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index e1e0d5a614195..d7634556f3a37 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -16,6 +16,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase { + /** @var Parser */ protected $parser; protected function setUp() @@ -1143,6 +1144,17 @@ public function parserThrowsExceptionWithCorrectLineNumberProvider() ), ); } + + public function testCanParseVeryLongValue() + { + $longStringWithSpaces = str_repeat('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ', 20000); + $trickyVal = array('x' => $longStringWithSpaces); + + $yamlString = Yaml::dump($trickyVal); + $arrayFromYaml = $this->parser->parse($yamlString); + + $this->assertEquals($trickyVal, $arrayFromYaml); + } } class B From b0ba6981117a808db47be1e731faa470e08e4449 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Fri, 17 Mar 2017 17:52:43 +0100 Subject: [PATCH 23/88] [WebProfilerBundle] Handle Content-Security-Policy-Report-Only header correctly --- .../Csp/ContentSecurityPolicyHandler.php | 5 +++++ .../Csp/ContentSecurityPolicyHandlerTest.php | 16 ++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Csp/ContentSecurityPolicyHandler.php b/src/Symfony/Bundle/WebProfilerBundle/Csp/ContentSecurityPolicyHandler.php index 52168924d3303..782a393e6a978 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Csp/ContentSecurityPolicyHandler.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Csp/ContentSecurityPolicyHandler.php @@ -108,6 +108,7 @@ private function removeCspHeaders(Response $response) { $response->headers->remove('X-Content-Security-Policy'); $response->headers->remove('Content-Security-Policy'); + $response->headers->remove('Content-Security-Policy-Report-Only'); } /** @@ -257,6 +258,10 @@ private function getCspHeaders(Response $response) $headers['Content-Security-Policy'] = $this->parseDirectives($response->headers->get('Content-Security-Policy')); } + if ($response->headers->has('Content-Security-Policy-Report-Only')) { + $headers['Content-Security-Policy-Report-Only'] = $this->parseDirectives($response->headers->get('Content-Security-Policy-Report-Only')); + } + if ($response->headers->has('X-Content-Security-Policy')) { $headers['X-Content-Security-Policy'] = $this->parseDirectives($response->headers->get('X-Content-Security-Policy')); } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php index eb91f5d357570..51397783699ea 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php @@ -97,41 +97,41 @@ public function provideRequestAndResponsesForOnKernelResponse() array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce), $this->createRequest(), $this->createResponse(), - array('Content-Security-Policy' => null, 'X-Content-Security-Policy' => null), + array('Content-Security-Policy' => null, 'Content-Security-Policy-Report-Only' => null, 'X-Content-Security-Policy' => null), ), array( $nonce, array('csp_script_nonce' => $requestScriptNonce, 'csp_style_nonce' => $requestStyleNonce), $this->createRequest($requestNonceHeaders), $this->createResponse($responseNonceHeaders), - array('Content-Security-Policy' => null, 'X-Content-Security-Policy' => null), + array('Content-Security-Policy' => null, 'Content-Security-Policy-Report-Only' => null, 'X-Content-Security-Policy' => null), ), array( $nonce, array('csp_script_nonce' => $requestScriptNonce, 'csp_style_nonce' => $requestStyleNonce), $this->createRequest($requestNonceHeaders), $this->createResponse(), - array('Content-Security-Policy' => null, 'X-Content-Security-Policy' => null), + array('Content-Security-Policy' => null, 'Content-Security-Policy-Report-Only' => null, 'X-Content-Security-Policy' => null), ), array( $nonce, array('csp_script_nonce' => $responseScriptNonce, 'csp_style_nonce' => $responseStyleNonce), $this->createRequest(), $this->createResponse($responseNonceHeaders), - array('Content-Security-Policy' => null, 'X-Content-Security-Policy' => null), + array('Content-Security-Policy' => null, 'Content-Security-Policy-Report-Only' => null, 'X-Content-Security-Policy' => null), ), array( $nonce, array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce), $this->createRequest(), - $this->createResponse(array('Content-Security-Policy' => 'frame-ancestors https: ; form-action: https:')), - array('Content-Security-Policy' => 'frame-ancestors https: ; form-action: https:', 'X-Content-Security-Policy' => null), + $this->createResponse(array('Content-Security-Policy' => 'frame-ancestors https: ; form-action: https:', 'Content-Security-Policy-Report-Only' => 'frame-ancestors http: ; form-action: http:')), + array('Content-Security-Policy' => 'frame-ancestors https: ; form-action: https:', 'Content-Security-Policy-Report-Only' => 'frame-ancestors http: ; form-action: http:', 'X-Content-Security-Policy' => null), ), array( $nonce, array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce), $this->createRequest(), - $this->createResponse(array('Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'')), - array('Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; style-src \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null), + $this->createResponse(array('Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'')), + array('Content-Security-Policy' => 'default-src \'self\' domain.com; script-src \'self\' \'unsafe-inline\'; style-src \'self\' domain.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy-Report-Only' => 'default-src \'self\' domain-report-only.com; script-src \'self\' \'unsafe-inline\'; style-src \'self\' domain-report-only.com \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null), ), array( $nonce, From 923bbdbf9f50975adf5a351d2bd39c787c89aa3b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 17 Mar 2017 23:14:15 +0100 Subject: [PATCH 24/88] [Security] simplify the SwitchUserListenerTest --- .../Tests/Firewall/SwitchUserListenerTest.php | 201 +++++------------- 1 file changed, 53 insertions(+), 148 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php index 2c05ef75cab25..43013520c36ba 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php @@ -12,6 +12,13 @@ namespace Symfony\Component\Security\Http\Tests\Firewall; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Component\Security\Core\Role\SwitchUserRole; +use Symfony\Component\Security\Core\User\User; use Symfony\Component\Security\Http\Event\SwitchUserEvent; use Symfony\Component\Security\Http\Firewall\SwitchUserListener; use Symfony\Component\Security\Http\SecurityEvents; @@ -32,14 +39,12 @@ class SwitchUserListenerTest extends TestCase protected function setUp() { - $this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock(); + $this->tokenStorage = new TokenStorage(); $this->userProvider = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserProviderInterface')->getMock(); $this->userChecker = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserCheckerInterface')->getMock(); $this->accessDecisionManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')->getMock(); - $this->request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock(); - $this->request->query = $this->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')->getMock(); - $this->request->server = $this->getMockBuilder('Symfony\Component\HttpFoundation\ServerBag')->getMock(); - $this->event = $this->getEvent($this->request); + $this->request = new Request(); + $this->event = new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $this->request, HttpKernelInterface::MASTER_REQUEST); } /** @@ -53,13 +58,11 @@ public function testProviderKeyIsRequired() public function testEventIsIgnoredIfUsernameIsNotPassedWithTheRequest() { - $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue(null)); - - $this->event->expects($this->never())->method('setResponse'); - $this->tokenStorage->expects($this->never())->method('setToken'); - $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); + + $this->assertNull($this->event->getResponse()); + $this->assertNull($this->tokenStorage->getToken()); } /** @@ -67,10 +70,10 @@ public function testEventIsIgnoredIfUsernameIsNotPassedWithTheRequest() */ public function testExitUserThrowsAuthenticationExceptionIfOriginalTokenCannotBeFound() { - $token = $this->getToken(array($this->getMockBuilder('Symfony\Component\Security\Core\Role\RoleInterface')->getMock())); + $token = new UsernamePasswordToken('username', '', 'key', array('ROLE_FOO')); - $this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token)); - $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('_exit')); + $this->tokenStorage->setToken($token); + $this->request->query->set('_switch_user', '_exit'); $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); @@ -78,29 +81,19 @@ public function testExitUserThrowsAuthenticationExceptionIfOriginalTokenCannotBe public function testExitUserUpdatesToken() { - $originalToken = $this->getToken(); - $role = $this->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole') - ->disableOriginalConstructor() - ->getMock(); - $role->expects($this->any())->method('getSource')->will($this->returnValue($originalToken)); - - $this->tokenStorage->expects($this->any()) - ->method('getToken') - ->will($this->returnValue($this->getToken(array($role)))); - - $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('_exit')); - $this->request->expects($this->any())->method('getUri')->will($this->returnValue('/')); - $this->request->query->expects($this->once())->method('remove', '_switch_user'); - $this->request->query->expects($this->any())->method('all')->will($this->returnValue(array())); - $this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', ''); - - $this->tokenStorage->expects($this->once()) - ->method('setToken')->with($originalToken); - $this->event->expects($this->once()) - ->method('setResponse')->with($this->isInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse')); + $originalToken = new UsernamePasswordToken('username', '', 'key', array()); + $this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', array(new SwitchUserRole('ROLE_PREVIOUS', $originalToken)))); + + $this->request->query->set('_switch_user', '_exit'); $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); + + $this->assertSame(array(), $this->request->query->all()); + $this->assertSame('', $this->request->server->get('QUERY_STRING')); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $this->event->getResponse()); + $this->assertSame($this->request->getUri(), $this->event->getResponse()->getTargetUrl()); + $this->assertSame($originalToken, $this->tokenStorage->getToken()); } public function testExitUserDispatchesEventWithRefreshedUser() @@ -113,38 +106,9 @@ public function testExitUserDispatchesEventWithRefreshedUser() ->method('refreshUser') ->with($originalUser) ->willReturn($refreshedUser); - $originalToken = $this->getToken(); - $originalToken - ->expects($this->any()) - ->method('getUser') - ->willReturn($originalUser); - $role = $this - ->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole') - ->disableOriginalConstructor() - ->getMock(); - $role->expects($this->any())->method('getSource')->willReturn($originalToken); - $this - ->tokenStorage - ->expects($this->any()) - ->method('getToken') - ->willReturn($this->getToken(array($role))); - $this - ->request - ->expects($this->any()) - ->method('get') - ->with('_switch_user') - ->willReturn('_exit'); - $this - ->request - ->expects($this->any()) - ->method('getUri') - ->willReturn('/'); - $this - ->request - ->query - ->expects($this->any()) - ->method('all') - ->will($this->returnValue(array())); + $originalToken = new UsernamePasswordToken($originalUser, '', 'key'); + $this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', array(new SwitchUserRole('ROLE_PREVIOUS', $originalToken)))); + $this->request->query->set('_switch_user', '_exit'); $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); $dispatcher @@ -166,41 +130,9 @@ public function testExitUserDoesNotDispatchEventWithStringUser() ->userProvider ->expects($this->never()) ->method('refreshUser'); - $originalToken = $this->getToken(); - $originalToken - ->expects($this->any()) - ->method('getUser') - ->willReturn($originalUser); - $role = $this - ->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole') - ->disableOriginalConstructor() - ->getMock(); - $role - ->expects($this->any()) - ->method('getSource') - ->willReturn($originalToken); - $this - ->tokenStorage - ->expects($this->any()) - ->method('getToken') - ->willReturn($this->getToken(array($role))); - $this - ->request - ->expects($this->any()) - ->method('get') - ->with('_switch_user') - ->willReturn('_exit'); - $this - ->request - ->query - ->expects($this->any()) - ->method('all') - ->will($this->returnValue(array())); - $this - ->request - ->expects($this->any()) - ->method('getUri') - ->willReturn('/'); + $originalToken = new UsernamePasswordToken($originalUser, '', 'key'); + $this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', array(new SwitchUserRole('ROLE_PREVIOUS', $originalToken)))); + $this->request->query->set('_switch_user', '_exit'); $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); $dispatcher @@ -217,10 +149,10 @@ public function testExitUserDoesNotDispatchEventWithStringUser() */ public function testSwitchUserIsDisallowed() { - $token = $this->getToken(array($this->getMockBuilder('Symfony\Component\Security\Core\Role\RoleInterface')->getMock())); + $token = new UsernamePasswordToken('username', '', 'key', array('ROLE_FOO')); - $this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token)); - $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba')); + $this->tokenStorage->setToken($token); + $this->request->query->set('_switch_user', 'kuba'); $this->accessDecisionManager->expects($this->once()) ->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH')) @@ -232,17 +164,11 @@ public function testSwitchUserIsDisallowed() public function testSwitchUser() { - $token = $this->getToken(array($this->getMockBuilder('Symfony\Component\Security\Core\Role\RoleInterface')->getMock())); - $user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(); - $user->expects($this->any())->method('getRoles')->will($this->returnValue(array())); + $token = new UsernamePasswordToken('username', '', 'key', array('ROLE_FOO')); + $user = new User('username', 'password', array()); - $this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token)); - $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba')); - $this->request->query->expects($this->once())->method('remove', '_switch_user'); - $this->request->query->expects($this->any())->method('all')->will($this->returnValue(array())); - - $this->request->expects($this->any())->method('getUri')->will($this->returnValue('/')); - $this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', ''); + $this->tokenStorage->setToken($token); + $this->request->query->set('_switch_user', 'kuba'); $this->accessDecisionManager->expects($this->once()) ->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH')) @@ -253,25 +179,26 @@ public function testSwitchUser() ->will($this->returnValue($user)); $this->userChecker->expects($this->once()) ->method('checkPostAuth')->with($user); - $this->tokenStorage->expects($this->once()) - ->method('setToken')->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken')); $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); + + $this->assertSame(array(), $this->request->query->all()); + $this->assertSame('', $this->request->server->get('QUERY_STRING')); + $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $this->tokenStorage->getToken()); } public function testSwitchUserKeepsOtherQueryStringParameters() { - $token = $this->getToken(array($this->getMockBuilder('Symfony\Component\Security\Core\Role\RoleInterface')->getMock())); - $user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(); - $user->expects($this->any())->method('getRoles')->will($this->returnValue(array())); + $token = new UsernamePasswordToken('username', '', 'key', array('ROLE_FOO')); + $user = new User('username', 'password', array()); - $this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token)); - $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba')); - $this->request->query->expects($this->once())->method('remove', '_switch_user'); - $this->request->query->expects($this->any())->method('all')->will($this->returnValue(array('page' => 3, 'section' => 2))); - $this->request->expects($this->any())->method('getUri')->will($this->returnValue('/')); - $this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', 'page=3§ion=2'); + $this->tokenStorage->setToken($token); + $this->request->query->replace(array( + '_switch_user' => 'kuba', + 'page' => 3, + 'section' => 2, + )); $this->accessDecisionManager->expects($this->once()) ->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH')) @@ -282,33 +209,11 @@ public function testSwitchUserKeepsOtherQueryStringParameters() ->will($this->returnValue($user)); $this->userChecker->expects($this->once()) ->method('checkPostAuth')->with($user); - $this->tokenStorage->expects($this->once()) - ->method('setToken')->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken')); $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); - } - - private function getEvent($request) - { - $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent') - ->disableOriginalConstructor() - ->getMock(); - - $event->expects($this->any()) - ->method('getRequest') - ->will($this->returnValue($request)); - - return $event; - } - - private function getToken(array $roles = array()) - { - $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock(); - $token->expects($this->any()) - ->method('getRoles') - ->will($this->returnValue($roles)); - return $token; + $this->assertSame('page=3§ion=2', $this->request->server->get('QUERY_STRING')); + $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $this->tokenStorage->getToken()); } } From 58b3ee7616f14473841b257eda776bbee712a960 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 20 Mar 2017 09:19:13 +0100 Subject: [PATCH 25/88] [DI] Fix PhpDumper generated doc block --- src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php | 2 +- .../DependencyInjection/Tests/Fixtures/php/services24.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index da9ab4315673f..888e1443944ee 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -628,7 +628,7 @@ private function addService($id, Definition $definition) } if ($definition->isAutowired()) { - $doc = << Date: Mon, 20 Mar 2017 10:41:03 +0100 Subject: [PATCH 26/88] [Yaml] CS --- src/Symfony/Component/Yaml/Parser.php | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 7f5c9baef1481..345bcbdac1731 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -257,7 +257,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = return $value; } - throw new ParseException('Unable to parse', $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } } @@ -636,10 +636,7 @@ private function isNextLineIndented() return false; } - $ret = false; - if ($this->getCurrentLineIndentation() > $currentIndentation) { - $ret = true; - } + $ret = $this->getCurrentLineIndentation() > $currentIndentation; $this->moveToPreviousLine(); @@ -740,14 +737,7 @@ private function isNextLineUnIndentedCollection() return false; } - $ret = false; - if ( - $this->getCurrentLineIndentation() == $currentIndentation - && - $this->isStringUnIndentedCollectionItem() - ) { - $ret = true; - } + $ret = $this->getCurrentLineIndentation() === $currentIndentation && $this->isStringUnIndentedCollectionItem(); $this->moveToPreviousLine(); @@ -789,8 +779,7 @@ private function isBlockScalarHeader() */ public static function preg_match($pattern, $subject, &$matches = null, $flags = 0, $offset = 0) { - $ret = preg_match($pattern, $subject, $matches, $flags, $offset); - if ($ret === false) { + if (false === $ret = preg_match($pattern, $subject, $matches, $flags, $offset)) { switch (preg_last_error()) { case PREG_INTERNAL_ERROR: $error = 'Internal PCRE error.'; From 1c2ea9758544e9839d0f85904c7d6339f37f902b Mon Sep 17 00:00:00 2001 From: Jordan Samouh Date: Wed, 15 Mar 2017 18:00:14 +0100 Subject: [PATCH 27/88] [DI] [YamlFileLoader] change error message of a non existing file --- .../Loader/YamlFileLoader.php | 2 +- .../Tests/Loader/YamlFileLoaderTest.php | 47 +++++++++---------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index fef1426d03a2f..d93891e9c8c52 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -319,7 +319,7 @@ protected function loadFile($file) } if (!file_exists($file)) { - throw new InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file)); + throw new InvalidArgumentException(sprintf('The file "%s" does not exist.', $file)); } if (null === $this->yamlParser) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 85a52ad1c245a..644c8711b78b1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -33,40 +33,33 @@ public static function setUpBeforeClass() require_once self::$fixturesPath.'/includes/ProjectExtension.php'; } - public function testLoadFile() + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /The file ".+" does not exist./ + */ + public function testLoadUnExistFile() { $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/ini')); $r = new \ReflectionObject($loader); $m = $r->getMethod('loadFile'); $m->setAccessible(true); - try { - $m->invoke($loader, 'foo.yml'); - $this->fail('->load() throws an InvalidArgumentException if the loaded file does not exist'); - } catch (\Exception $e) { - $this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the loaded file does not exist'); - $this->assertEquals('The service file "foo.yml" is not valid.', $e->getMessage(), '->load() throws an InvalidArgumentException if the loaded file does not exist'); - } - - try { - $m->invoke($loader, 'parameters.ini'); - $this->fail('->load() throws an InvalidArgumentException if the loaded file is not a valid YAML file'); - } catch (\Exception $e) { - $this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the loaded file is not a valid YAML file'); - $this->assertEquals('The service file "parameters.ini" is not valid.', $e->getMessage(), '->load() throws an InvalidArgumentException if the loaded file is not a valid YAML file'); - } + $m->invoke($loader, 'foo.yml'); + } - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + * @expectedExceptionMessageRegExp /The file ".+" does not contain valid YAML./ + */ + public function testLoadInvalidYamlFile() + { + $path = self::$fixturesPath.'/ini'; + $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator($path)); + $r = new \ReflectionObject($loader); + $m = $r->getMethod('loadFile'); + $m->setAccessible(true); - foreach (array('nonvalid1', 'nonvalid2') as $fixture) { - try { - $m->invoke($loader, $fixture.'.yml'); - $this->fail('->load() throws an InvalidArgumentException if the loaded file does not validate'); - } catch (\Exception $e) { - $this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the loaded file does not validate'); - $this->assertStringMatchesFormat('The service file "nonvalid%d.yml" is not valid.', $e->getMessage(), '->load() throws an InvalidArgumentException if the loaded file does not validate'); - } - } + $m->invoke($loader, $path.'/parameters.ini'); } /** @@ -90,6 +83,8 @@ public function provideInvalidFiles() array('bad_service'), array('bad_calls'), array('bad_format'), + array('nonvalid1'), + array('nonvalid2'), ); } From abf1787dcc3a8ecbad31b07792f4bec1a8fed4c8 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 18 Mar 2017 10:10:35 +0100 Subject: [PATCH 28/88] fix some risky tests --- .../HttpFoundation/DbalSessionHandlerTest.php | 2 + ...xtensionBootstrap3HorizontalLayoutTest.php | 14 ++--- .../FormExtensionBootstrap3LayoutTest.php | 14 ++--- .../Extension/FormExtensionDivLayoutTest.php | 20 ++++--- .../FormExtensionTableLayoutTest.php | 14 ++--- .../Helper/FormHelperDivLayoutTest.php | 14 ++--- .../Helper/FormHelperTableLayoutTest.php | 14 ++--- .../Templating/Helper/StopwatchHelperTest.php | 9 ++-- .../Tests/Templating/TemplateTest.php | 16 +----- .../Console/Tests/ApplicationTest.php | 4 ++ .../Console/Tests/Helper/TableTest.php | 8 +-- .../CheckCircularReferencesPassTest.php | 2 + .../CheckDefinitionValidityPassTest.php | 4 ++ ...tionOnInvalidReferenceBehaviorPassTest.php | 4 ++ .../CheckReferenceValidityPassTest.php | 8 +++ .../Tests/Dumper/PhpDumperTest.php | 4 ++ .../Tests/Dumper/XmlDumperTest.php | 2 + .../Debug/TraceableEventDispatcherTest.php | 6 +++ .../Filesystem/Tests/FilesystemTest.php | 40 +++++++++++--- .../Form/Tests/AbstractLayoutTest.php | 2 + .../Tests/Resources/TranslationFilesTest.php | 2 + .../Fragment/InlineFragmentRendererTest.php | 52 +++++++++++-------- .../Tests/LegacyOptionsResolverTest.php | 4 +- .../Tests/OptionsResolver2Dot6Test.php | 10 ++-- .../PropertyAccess/Tests/PropertyPathTest.php | 4 +- .../Tests/Resources/TranslationFilesTest.php | 2 + .../Tests/Resources/TranslationFilesTest.php | 2 + .../Tests/Encoder/XmlEncoderTest.php | 20 ++----- .../Tests/PluralizationRulesTest.php | 2 - .../Translation/Tests/TranslatorTest.php | 3 ++ .../Validator/Tests/ConstraintTest.php | 8 ++- .../Constraints/CallbackValidatorTest.php | 4 +- .../Tests/Constraints/GroupSequenceTest.php | 2 + .../Tests/Mapping/ClassMetadataTest.php | 12 +++-- .../LazyLoadingMetadataFactoryTest.php | 4 ++ .../Tests/Resources/TranslationFilesTest.php | 2 + 36 files changed, 206 insertions(+), 128 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/HttpFoundation/DbalSessionHandlerTest.php b/src/Symfony/Bridge/Doctrine/Tests/HttpFoundation/DbalSessionHandlerTest.php index 89ac999f20301..1c9c82bc129e6 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/HttpFoundation/DbalSessionHandlerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/HttpFoundation/DbalSessionHandlerTest.php @@ -25,5 +25,7 @@ public function testConstruct() { $connection = $this->getMockBuilder('Doctrine\DBAL\Connection')->disableOriginalConstructor()->getMock(); $handler = new DbalSessionHandler($connection); + + $this->assertInstanceOf('Symfony\Bridge\Doctrine\HttpFoundation\DbalSessionHandler', $handler); } } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php index 2951e4471f731..8abcc8cd5677b 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php @@ -118,36 +118,36 @@ protected function setTheme(FormView $view, array $themes) public function testRange() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testRangeWithMinMaxValues() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testLabelWithoutTranslationOnButton() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testButtonlabelWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testAttributesNotTranslatedWhenTranslationDomainIsFalse() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php index d26714530c954..0236dd76e1e46 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php @@ -118,36 +118,36 @@ protected function setTheme(FormView $view, array $themes) public function testRange() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testRangeWithMinMaxValues() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testLabelWithoutTranslationOnButton() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testButtonlabelWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testAttributesNotTranslatedWhenTranslationDomainIsFalse() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index 7e4c55e984b4a..d07e585a89234 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -105,7 +105,11 @@ public function testThemeBlockInheritanceUsingDynamicExtend() $renderer = $this->extension->renderer; $renderer->setTheme($view, array('page_dynamic_extends.html.twig')); - $renderer->searchAndRenderBlock($view, 'row'); + + $this->assertMatchesXpath( + $renderer->searchAndRenderBlock($view, 'row'), + '/div/label[text()="child"]' + ); } public function isSelectedChoiceProvider() @@ -211,36 +215,36 @@ public static function themeInheritanceProvider() public function testRange() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testRangeWithMinMaxValues() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testLabelWithoutTranslationOnButton() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testButtonlabelWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testAttributesNotTranslatedWhenTranslationDomainIsFalse() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php index 6509c405e7bc9..9c95db6d5fd9d 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php @@ -119,36 +119,36 @@ protected function setTheme(FormView $view, array $themes) public function testRange() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testRangeWithMinMaxValues() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testLabelWithoutTranslationOnButton() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testButtonlabelWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testAttributesNotTranslatedWhenTranslationDomainIsFalse() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php index 217fd5e50e237..c745818b1e72b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @@ -131,36 +131,36 @@ public static function themeInheritanceProvider() public function testRange() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testRangeWithMinMaxValues() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testLabelWithoutTranslationOnButton() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testButtonlabelWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testAttributesNotTranslatedWhenTranslationDomainIsFalse() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php index 99bfba0c4e7cc..3448a56fa4d2d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @@ -118,36 +118,36 @@ protected function setTheme(FormView $view, array $themes) public function testRange() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testRangeWithMinMaxValues() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testLabelWithoutTranslationOnButton() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testSingleChoiceExpandedWithPlaceholderWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testButtonlabelWithoutTranslation() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } public function testAttributesNotTranslatedWhenTranslationDomainIsFalse() { - // No-op for forward compatibility with AbstractLayoutTest 2.8 + $this->markTestIncomplete('No-op for forward compatibility with AbstractLayoutTest 2.8'); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/StopwatchHelperTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/StopwatchHelperTest.php index cf7b627a499a6..686c655aac8f2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/StopwatchHelperTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/StopwatchHelperTest.php @@ -30,11 +30,10 @@ public function testDevEnvironment() public function testProdEnvironment() { $helper = new StopwatchHelper(null); + $helper->start('foo'); - try { - $helper->start('foo'); - } catch (\BadMethodCallException $e) { - $this->fail('Assumed stopwatch is not called when not provided'); - } + // add a dummy assertion here to satisfy PHPUnit, the only thing we want to test is that the code above + // can be executed without throwing any exceptions + $this->addToAssertionCount(1); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateTest.php index c49010bfdc357..1f6f51dd3351d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateTest.php @@ -19,21 +19,9 @@ class TemplateTest extends TestCase /** * @dataProvider getTemplateToPathProvider */ - public function testGetPathForTemplatesInABundle($template, $path) + public function testGetPathForTemplate($template, $path) { - if ($template->get('bundle')) { - $this->assertEquals($template->getPath(), $path); - } - } - - /** - * @dataProvider getTemplateToPathProvider - */ - public function testGetPathForTemplatesOutOfABundle($template, $path) - { - if (!$template->get('bundle')) { - $this->assertEquals($template->getPath(), $path); - } + $this->assertSame($template->getPath(), $path); } public function getTemplateToPathProvider() diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 223a68bfc8e29..895fdb926142f 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -704,8 +704,12 @@ public function testVerboseValueNotBreakArguments() $input = new ArgvInput(array('cli.php', '-v', 'foo:bar')); $application->run($input, $output); + $this->addToAssertionCount(1); + $input = new ArgvInput(array('cli.php', '--verbose', 'foo:bar')); $application->run($input, $output); + + $this->addToAssertionCount(1); } public function testRunReturnsIntegerExitCode() diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 2ff581e83ef8b..5fe6b645602fa 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -34,7 +34,7 @@ protected function tearDown() } /** - * @dataProvider testRenderProvider + * @dataProvider renderProvider */ public function testRender($headers, $rows, $style, $expected, $decorated = false) { @@ -50,7 +50,7 @@ public function testRender($headers, $rows, $style, $expected, $decorated = fals } /** - * @dataProvider testRenderProvider + * @dataProvider renderProvider */ public function testRenderAddRows($headers, $rows, $style, $expected, $decorated = false) { @@ -66,7 +66,7 @@ public function testRenderAddRows($headers, $rows, $style, $expected, $decorated } /** - * @dataProvider testRenderProvider + * @dataProvider renderProvider */ public function testRenderAddRowsOneByOne($headers, $rows, $style, $expected, $decorated = false) { @@ -83,7 +83,7 @@ public function testRenderAddRowsOneByOne($headers, $rows, $style, $expected, $d $this->assertEquals($expected, $this->getOutputContent($output)); } - public function testRenderProvider() + public function renderProvider() { $books = array( array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'), diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckCircularReferencesPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckCircularReferencesPassTest.php index d894f7ab6f6d0..220348f4fecf2 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckCircularReferencesPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckCircularReferencesPassTest.php @@ -114,6 +114,8 @@ public function testProcessIgnoresMethodCalls() $container->register('b')->addMethodCall('setA', array(new Reference('a'))); $this->process($container); + + $this->addToAssertionCount(1); } protected function process(ContainerBuilder $container) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php index 60f44c3f02248..f7889e94967b2 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php @@ -72,6 +72,8 @@ public function testProcess() $container->register('d', 'class')->setSynthetic(true); $this->process($container); + + $this->addToAssertionCount(1); } public function testValidTags() @@ -83,6 +85,8 @@ public function testValidTags() $container->register('d', 'class')->addTag('foo', array('bar' => 1.1)); $this->process($container); + + $this->addToAssertionCount(1); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php index c5f4ec7f95690..65a782a4a83fc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php @@ -28,6 +28,10 @@ public function testProcess() ->addArgument(new Reference('b')) ; $container->register('b', '\stdClass'); + + $this->process($container); + + $this->addToAssertionCount(1); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckReferenceValidityPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckReferenceValidityPassTest.php index d7e15df9e43a3..303787bea19b2 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckReferenceValidityPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckReferenceValidityPassTest.php @@ -27,6 +27,8 @@ public function testProcessIgnoresScopeWideningIfNonStrictReference() $container->register('b')->setScope('prototype'); $this->process($container); + + $this->addToAssertionCount(1); } /** @@ -39,6 +41,8 @@ public function testProcessDetectsScopeWidening() $container->register('b')->setScope('prototype'); $this->process($container); + + $this->addToAssertionCount(1); } public function testProcessIgnoresCrossScopeHierarchyReferenceIfNotStrict() @@ -51,6 +55,8 @@ public function testProcessIgnoresCrossScopeHierarchyReferenceIfNotStrict() $container->register('b')->setScope('b'); $this->process($container); + + $this->addToAssertionCount(1); } /** @@ -88,6 +94,8 @@ public function testProcess() $container->register('b'); $this->process($container); + + $this->addToAssertionCount(1); } protected function process(ContainerBuilder $container) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 7d660fb2f02e2..41b6c375d8aab 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -297,6 +297,8 @@ public function testCircularReferenceAllowanceForLazyServices() $dumper = new PhpDumper($container); $dumper->dump(); + + $this->addToAssertionCount(1); } public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServices() @@ -334,5 +336,7 @@ public function testCircularReferenceAllowanceForInlinedDefinitionsForLazyServic $dumper->setProxyDumper(new DummyProxyDumper()); $dumper->dump(); + + $this->addToAssertionCount(1); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php index 9f96f33e9dece..72ae5897204f1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php @@ -162,6 +162,8 @@ public function testCompiledContainerCanBeDumped($containerFile) $container->compile(); $dumper = new XmlDumper($container); $dumper->dump(); + + $this->addToAssertionCount(1); } public function provideCompiledContainerData() diff --git a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php index 9ee85bb0ac254..9317ea9457225 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php @@ -151,14 +151,20 @@ public function testDispatchNested() { $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); $loop = 1; + $dispatchedEvents = 0; $dispatcher->addListener('foo', $listener1 = function () use ($dispatcher, &$loop) { ++$loop; if (2 == $loop) { $dispatcher->dispatch('foo'); } }); + $dispatcher->addListener('foo', function () use (&$dispatchedEvents) { + ++$dispatchedEvents; + }); $dispatcher->dispatch('foo'); + + $this->assertSame(2, $dispatchedEvents); } public function testDispatchReusedEventNested() diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index f879e641701eb..be47a2d0ce724 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -442,14 +442,22 @@ public function testChmodChangesFileMode() $this->assertFilePermissions(400, $file); } - public function testChmodWrongMod() + public function testChmodWithWrongModLeavesPreviousPermissionsUntouched() { $this->markAsSkippedIfChmodIsMissing(); + if (defined('HHVM_VERSION')) { + $this->markTestSkipped('chmod() changes permissions even when passing invalid modes on HHVM'); + } + $dir = $this->workspace.DIRECTORY_SEPARATOR.'file'; touch($dir); + $permissions = fileperms($dir); + $this->filesystem->chmod($dir, 'Wrongmode'); + + $this->assertSame($permissions, fileperms($dir)); } public function testChmodRecursive() @@ -536,7 +544,10 @@ public function testChown() $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir'; mkdir($dir); - $this->filesystem->chown($dir, $this->getFileOwner($dir)); + $owner = $this->getFileOwner($dir); + $this->filesystem->chown($dir, $owner); + + $this->assertSame($owner, $this->getFileOwner($dir)); } public function testChownRecursive() @@ -548,7 +559,10 @@ public function testChownRecursive() $file = $dir.DIRECTORY_SEPARATOR.'file'; touch($file); - $this->filesystem->chown($dir, $this->getFileOwner($dir), true); + $owner = $this->getFileOwner($dir); + $this->filesystem->chown($dir, $owner, true); + + $this->assertSame($owner, $this->getFileOwner($file)); } public function testChownSymlink() @@ -562,7 +576,10 @@ public function testChownSymlink() $this->filesystem->symlink($file, $link); - $this->filesystem->chown($link, $this->getFileOwner($link)); + $owner = $this->getFileOwner($link); + $this->filesystem->chown($link, $owner); + + $this->assertSame($owner, $this->getFileOwner($link)); } /** @@ -602,7 +619,10 @@ public function testChgrp() $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir'; mkdir($dir); - $this->filesystem->chgrp($dir, $this->getFileGroup($dir)); + $group = $this->getFileGroup($dir); + $this->filesystem->chgrp($dir, $group); + + $this->assertSame($group, $this->getFileGroup($dir)); } public function testChgrpRecursive() @@ -614,7 +634,10 @@ public function testChgrpRecursive() $file = $dir.DIRECTORY_SEPARATOR.'file'; touch($file); - $this->filesystem->chgrp($dir, $this->getFileGroup($dir), true); + $group = $this->getFileGroup($dir); + $this->filesystem->chgrp($dir, $group, true); + + $this->assertSame($group, $this->getFileGroup($file)); } public function testChgrpSymlink() @@ -628,7 +651,10 @@ public function testChgrpSymlink() $this->filesystem->symlink($file, $link); - $this->filesystem->chgrp($link, $this->getFileGroup($link)); + $group = $this->getFileGroup($link); + $this->filesystem->chgrp($link, $group); + + $this->assertSame($group, $this->getFileGroup($link)); } /** diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 3873fb4cd4dc8..411a8196cc73d 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -83,6 +83,8 @@ protected function assertMatchesXpath($html, $expression, $count = 1) // strip away and substr($dom->saveHTML(), 6, -8) )); + } else { + $this->addToAssertionCount(1); } } diff --git a/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php index 052821c39dfec..ba19a6215a7b4 100644 --- a/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php @@ -25,6 +25,8 @@ public function testTranslationFileIsValid($filePath) } else { \PHPUnit\Util\XML::loadfile($filePath, false, false, true); } + + $this->addToAssertionCount(1); } public function provideTranslationFiles() diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php index f85fd5ed26fd3..4c1d6a00c44c9 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php @@ -22,6 +22,18 @@ class InlineFragmentRendererTest extends TestCase { + private $originalTrustedHeaderName; + + protected function setUp() + { + $this->originalTrustedHeaderName = Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP); + } + + protected function tearDown() + { + Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, $this->originalTrustedHeaderName); + } + public function testRender() { $strategy = new InlineFragmentRenderer($this->getKernel($this->returnValue(new Response('foo')))); @@ -47,7 +59,7 @@ public function testRenderWithObjectsAsAttributes() $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest)); - $strategy->render(new ControllerReference('main_controller', array('object' => $object), array()), Request::create('/')); + $this->assertSame('foo', $strategy->render(new ControllerReference('main_controller', array('object' => $object), array()), Request::create('/'))->getContent()); } public function testRenderWithObjectsAsAttributesPassedAsObjectsInTheController() @@ -70,14 +82,10 @@ public function testRenderWithObjectsAsAttributesPassedAsObjectsInTheController( public function testRenderWithTrustedHeaderDisabled() { - $trustedHeaderName = Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, ''); $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest(Request::create('/'))); - $strategy->render('/', Request::create('/')); - - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, $trustedHeaderName); + $this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent()); } /** @@ -125,22 +133,6 @@ private function getKernel($returnValue) return $kernel; } - /** - * Creates a Kernel expecting a request equals to $request - * Allows delta in comparison in case REQUEST_TIME changed by 1 second. - */ - private function getKernelExpectingRequest(Request $request) - { - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); - $kernel - ->expects($this->any()) - ->method('handle') - ->with($this->equalTo($request, 1)) - ; - - return $kernel; - } - public function testExceptionInSubRequestsDoesNotMangleOutputBuffers() { $resolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface')->getMock(); @@ -211,6 +203,22 @@ public function testHeadersPossiblyResultingIn304AreNotAssignedToSubrequest() $request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*')); $strategy->render('/', $request); } + + /** + * Creates a Kernel expecting a request equals to $request + * Allows delta in comparison in case REQUEST_TIME changed by 1 second. + */ + private function getKernelExpectingRequest(Request $request, $strict = false) + { + $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $kernel + ->expects($this->once()) + ->method('handle') + ->with($this->equalTo($request, 1)) + ->willReturn(new Response('foo')); + + return $kernel; + } } class Bar diff --git a/src/Symfony/Component/OptionsResolver/Tests/LegacyOptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/LegacyOptionsResolverTest.php index c277425c4d7fa..44e07b7726c9b 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/LegacyOptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/LegacyOptionsResolverTest.php @@ -89,9 +89,9 @@ public function testTypeAliasesForAllowedTypes() 'force' => 'boolean', )); - $this->resolver->resolve(array( + $this->assertSame(array('force' => true), $this->resolver->resolve(array( 'force' => true, - )); + ))); } public function testResolveLazyDependencyOnOptional() diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolver2Dot6Test.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolver2Dot6Test.php index 109454e56ff62..c548f16ba6d90 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolver2Dot6Test.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolver2Dot6Test.php @@ -1102,7 +1102,7 @@ public function testFailIfCyclicDependencyBetweenNormalizerAndLazyOption() $this->resolver->resolve(); } - public function testCatchedExceptionFromNormalizerDoesNotCrashOptionResolver() + public function testCaughtExceptionFromNormalizerDoesNotCrashOptionResolver() { $throw = true; @@ -1116,7 +1116,7 @@ public function testCatchedExceptionFromNormalizerDoesNotCrashOptionResolver() } }); - $this->resolver->setNormalizer('thrower', function (Options $options) use (&$throw) { + $this->resolver->setNormalizer('thrower', function () use (&$throw) { if ($throw) { $throw = false; throw new \UnexpectedValueException('throwing'); @@ -1125,10 +1125,10 @@ public function testCatchedExceptionFromNormalizerDoesNotCrashOptionResolver() return true; }); - $this->resolver->resolve(); + $this->assertSame(array('catcher' => false, 'thrower' => true), $this->resolver->resolve()); } - public function testCatchedExceptionFromLazyDoesNotCrashOptionResolver() + public function testCaughtExceptionFromLazyDoesNotCrashOptionResolver() { $throw = true; @@ -1149,7 +1149,7 @@ public function testCatchedExceptionFromLazyDoesNotCrashOptionResolver() return true; }); - $this->resolver->resolve(); + $this->assertSame(array('catcher' => false, 'thrower' => true), $this->resolver->resolve()); } public function testInvokeEachNormalizerOnlyOnce() diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php index 5e3a06a4b4d85..6c5c6b22a2b06 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php @@ -87,7 +87,9 @@ public function testPathCannotBeFalse() public function testZeroIsValidPropertyPath() { - new PropertyPath('0'); + $propertyPath = new PropertyPath('0'); + + $this->assertSame('0', (string) $propertyPath); } public function testGetParentWithDot() diff --git a/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php index 6588c32fdfa3c..96a1307ed056b 100644 --- a/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php @@ -25,6 +25,8 @@ public function testTranslationFileIsValid($filePath) } else { \PHPUnit\Util\XML::loadfile($filePath, false, false, true); } + + $this->addToAssertionCount(1); } public function provideTranslationFiles() diff --git a/src/Symfony/Component/Security/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Security/Tests/Resources/TranslationFilesTest.php index 5e959b30d4fbc..30b9aed6ec873 100644 --- a/src/Symfony/Component/Security/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Security/Tests/Resources/TranslationFilesTest.php @@ -25,6 +25,8 @@ public function testTranslationFileIsValid($filePath) } else { \PHPUnit\Util\XML::loadfile($filePath, false, false, true); } + + $this->addToAssertionCount(1); } public function provideTranslationFiles() diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 4e83f3464f200..751afe2bd3e8f 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -17,7 +17,6 @@ use Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Serializer; -use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Normalizer\CustomNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; @@ -435,23 +434,12 @@ public function testDecodeInvalidXml() $this->encoder->decode('', 'xml'); } + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ public function testPreventsComplexExternalEntities() { - $oldCwd = getcwd(); - chdir(__DIR__); - - try { - $this->encoder->decode(']>&test;', 'xml'); - chdir($oldCwd); - - $this->fail('No exception was thrown.'); - } catch (\Exception $e) { - chdir($oldCwd); - - if (!$e instanceof UnexpectedValueException) { - $this->fail('Expected UnexpectedValueException'); - } - } + $this->encoder->decode(']>&test;', 'xml'); } public function testDecodeEmptyXml() diff --git a/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php b/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php index 8e499fd6edace..8a6723ea9cb1a 100644 --- a/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php +++ b/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php @@ -65,7 +65,6 @@ public function successLangcodes() array('2', array('nl', 'fr', 'en', 'de', 'de_GE', 'hy', 'hy_AM')), array('3', array('be', 'bs', 'cs', 'hr')), array('4', array('cy', 'mt', 'sl')), - array('5', array()), array('6', array('ar')), ); } @@ -86,7 +85,6 @@ public function failingLangcodes() array('3', array('cbs')), array('4', array('gd', 'kw')), array('5', array('ga')), - array('6', array()), ); } diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index f02eb57b358fe..960d8f4d3c549 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -156,6 +156,7 @@ public function testSetFallbackValidLocales($locale) $translator = new Translator($locale, new MessageSelector()); $translator->setFallbackLocales(array('fr', $locale)); // no assertion. this method just asserts that no exception is thrown + $this->addToAssertionCount(1); } public function testTransWithFallbackLocale() @@ -187,6 +188,7 @@ public function testAddResourceValidLocales($locale) $translator = new Translator('fr', new MessageSelector()); $translator->addResource('array', array('foo' => 'foofoo'), $locale); // no assertion. this method just asserts that no exception is thrown + $this->addToAssertionCount(1); } public function testAddResourceAfterTrans() @@ -390,6 +392,7 @@ public function testTransChoiceValidLocale($locale) $translator->transChoice('foo', 1, array(), '', $locale); // no assertion. this method just asserts that no exception is thrown + $this->addToAssertionCount(1); } public function getTransFileTests() diff --git a/src/Symfony/Component/Validator/Tests/ConstraintTest.php b/src/Symfony/Component/Validator/Tests/ConstraintTest.php index 1b1219664402b..a05741490fdde 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintTest.php @@ -115,7 +115,9 @@ public function testRequiredOptionsMustBeDefined() public function testRequiredOptionsPassed() { - new ConstraintC(array('option1' => 'default')); + $constraint = new ConstraintC(array('option1' => 'default')); + + $this->assertSame('default', $constraint->option1); } public function testGroupsAreConvertedToArray() @@ -140,7 +142,9 @@ public function testAllowsSettingZeroRequiredPropertyValue() public function testCanCreateConstraintWithNoDefaultOptionAndEmptyArray() { - new ConstraintB(array()); + $constraint = new ConstraintB(array()); + + $this->assertSame(array(Constraint::PROPERTY_CONSTRAINT, Constraint::CLASS_CONSTRAINT), $constraint->getTargets()); } public function testGetTargetsCanBeString() diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php index 6bd7735f0d7d5..e87c9c4752a2e 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php @@ -330,7 +330,9 @@ public function testConstraintGetTargets() // Should succeed. Needed when defining constraints as annotations. public function testNoConstructorArguments() { - new Callback(); + $constraint = new Callback(); + + $this->assertSame(array(Constraint::CLASS_CONSTRAINT, Constraint::PROPERTY_CONSTRAINT), $constraint->getTargets()); } public function testAnnotationInvocationSingleValued() diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GroupSequenceTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GroupSequenceTest.php index 6326d0514ba3e..f298cd27e6257 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/GroupSequenceTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/GroupSequenceTest.php @@ -94,5 +94,7 @@ public function testLegacyUnsetIgnoresNonExistingKeys() // should not fail unset($sequence[2]); + + $this->assertCount(2, $sequence); } } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php b/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php index 8ca3c9fbcb606..9a23e8cf355a0 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php @@ -245,19 +245,23 @@ public function testSerialize() public function testGroupSequencesWorkIfContainingDefaultGroup() { $this->metadata->setGroupSequence(array('Foo', $this->metadata->getDefaultGroup())); + + $this->assertInstanceOf('Symfony\Component\Validator\Constraints\GroupSequence', $this->metadata->getGroupSequence()); } + /** + * @expectedException \Symfony\Component\Validator\Exception\GroupDefinitionException + */ public function testGroupSequencesFailIfNotContainingDefaultGroup() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\GroupDefinitionException'); - $this->metadata->setGroupSequence(array('Foo', 'Bar')); } + /** + * @expectedException \Symfony\Component\Validator\Exception\GroupDefinitionException + */ public function testGroupSequencesFailIfContainingDefault() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\GroupDefinitionException'); - $this->metadata->setGroupSequence(array('Foo', $this->metadata->getDefaultGroup(), Constraint::DEFAULT_GROUP)); } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php index 1ebce65cc2029..b5d1a9dc84d4d 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php @@ -167,7 +167,11 @@ public function testMetadataCacheWithRuntimeConstraint() $metadata = $factory->getMetadataFor(self::PARENT_CLASS); $metadata->addConstraint(new Callback(function () {})); + $this->assertCount(3, $metadata->getConstraints()); + $metadata = $factory->getMetadataFor(self::CLASS_NAME); + + $this->assertCount(6, $metadata->getConstraints()); } public function testGroupsFromParent() diff --git a/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php index d33351352777c..96311cfeff326 100644 --- a/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php @@ -25,6 +25,8 @@ public function testTranslationFileIsValid($filePath) } else { \PHPUnit\Util\XML::loadfile($filePath, false, false, true); } + + $this->addToAssertionCount(1); } public function provideTranslationFiles() From f50915066f20d1a816a559def732929cfc537dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Auswo=CC=88ger?= Date: Mon, 20 Mar 2017 20:55:39 +0100 Subject: [PATCH 29/88] [HttpKernel] Fixed bug with purging of HTTPS URLs --- .../Component/HttpKernel/HttpCache/Store.php | 9 ++++--- .../HttpKernel/Tests/HttpCache/StoreTest.php | 27 +++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Store.php b/src/Symfony/Component/HttpKernel/HttpCache/Store.php index f5574614b839a..c4d961e68f043 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/Store.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/Store.php @@ -325,10 +325,13 @@ private function getMetadata($key) */ public function purge($url) { - $http = preg_replace('#^https#', 'http', $url); - $https = preg_replace('#^http#', 'https', $url); + $http = preg_replace('#^https:#', 'http:', $url); + $https = preg_replace('#^http:#', 'https:', $url); - return $this->doPurge($http) || $this->doPurge($https); + $purgedHttp = $this->doPurge($http); + $purgedHttps = $this->doPurge($https); + + return $purgedHttp || $purgedHttps; } /** diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php index 8b9e52b03ea9a..cef019167a4ef 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php @@ -236,6 +236,33 @@ public function testLocking() $this->assertFalse($this->store->isLocked($req)); } + public function testPurgeHttps() + { + $request = Request::create('https://example.com/foo'); + $this->store->write($request, new Response('foo')); + + $this->assertNotEmpty($this->getStoreMetadata($request)); + + $this->assertTrue($this->store->purge('https://example.com/foo')); + $this->assertEmpty($this->getStoreMetadata($request)); + } + + public function testPurgeHttpAndHttps() + { + $requestHttp = Request::create('https://example.com/foo'); + $this->store->write($requestHttp, new Response('foo')); + + $requestHttps = Request::create('http://example.com/foo'); + $this->store->write($requestHttps, new Response('foo')); + + $this->assertNotEmpty($this->getStoreMetadata($requestHttp)); + $this->assertNotEmpty($this->getStoreMetadata($requestHttps)); + + $this->assertTrue($this->store->purge('http://example.com/foo')); + $this->assertEmpty($this->getStoreMetadata($requestHttp)); + $this->assertEmpty($this->getStoreMetadata($requestHttps)); + } + protected function storeSimpleEntry($path = null, $headers = array()) { if (null === $path) { From 2de494f60bef82490a192bf81d10156269ac980e Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 21 Mar 2017 11:01:33 +0100 Subject: [PATCH 30/88] [WebProfilerBundle] Drop dead code --- .../Controller/ProfilerController.php | 2 +- .../views/Profiler/toolbar.html.twig | 64 +++++++++---------- 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php index 4e6f15bd01ee5..67767b0a78d7f 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php @@ -43,7 +43,7 @@ class ProfilerController * @param array $templates The templates * @param string $toolbarPosition The toolbar position (top, bottom, normal, or null -- use the configuration) */ - public function __construct(UrlGeneratorInterface $generator, Profiler $profiler = null, \Twig_Environment $twig, array $templates, $toolbarPosition = 'normal') + public function __construct(UrlGeneratorInterface $generator, Profiler $profiler = null, \Twig_Environment $twig, array $templates, $toolbarPosition = 'bottom') { $this->generator = $generator; $this->profiler = $profiler; diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig index 99ee7172ed291..b2b77f65fa062 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig @@ -1,28 +1,26 @@ -{% if 'normal' != position %} - - -
-{% endif %} + Sfjs.setPreference('toolbar/displayState', 'block'); + "> + {{ include('@WebProfiler/Icon/symfony.svg') }} + + + +
{% for name, template in templates %} @@ -39,16 +37,14 @@ {% endif %} {% endfor %} - {% if 'normal' != position %} - - {{ include('@WebProfiler/Icon/close.svg') }} - - {% endif %} + + {{ include('@WebProfiler/Icon/close.svg') }} +
From 4acec8973f0073184943a5050e0b32791f617f50 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 21 Mar 2017 11:08:09 +0100 Subject: [PATCH 31/88] [WebProfilerBundle] Fix content-security-policy compatibility This fixes the compatibility of the bundle in case of a `style-src 'self'` policy. --- .../Resources/views/Profiler/toolbar.html.twig | 3 --- .../Resources/views/Profiler/toolbar_js.html.twig | 3 +++ .../Tests/Controller/ProfilerControllerTest.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig index 181e359fa3f7e..a211617d7234d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.html.twig @@ -4,9 +4,6 @@ {{ include('@WebProfiler/Icon/symfony.svg') }} - - {{ include('@WebProfiler/Profiler/toolbar.css.twig', { 'position': position, 'floatable': true }) }} -
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig index ea038277c4bec..7dc541caae589 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig @@ -1,5 +1,8 @@
{{ include('@WebProfiler/Profiler/base_js.html.twig') }} + + {{ include('@WebProfiler/Profiler/toolbar.css.twig', { 'position': position, 'floatable': true }) }} + /*getMockBuilder('Symfony\Bundle\WebProfilerBundle\Csp\NonceGenerator')->getMock(); - return new ProfilerController($urlGenerator, $profiler, $twig, array(), 'normal', new ContentSecurityPolicyHandler($nonceGenerator)); + return new ProfilerController($urlGenerator, $profiler, $twig, array(), 'bottom', new ContentSecurityPolicyHandler($nonceGenerator)); } - return new ProfilerController($urlGenerator, $profiler, $twig, array(), 'normal'); + return new ProfilerController($urlGenerator, $profiler, $twig, array()); } } From b3f341fd908ea496dea0a77984bc4e31acc52f98 Mon Sep 17 00:00:00 2001 From: Romain Pierre Date: Tue, 21 Mar 2017 22:03:13 +0100 Subject: [PATCH 32/88] Fixes a typo in the form collector styles --- .../WebProfilerBundle/Resources/views/Collector/form.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig index eb87a8fa8abb1..a59982ce8a9e8 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig @@ -60,7 +60,7 @@ } #tree-menu .empty { border: 0; - mmargin: 0; + margin: 0; padding: 0; } #tree-details-container { From 0c741f570434606d5d539ac37c8be76b9e09e91a Mon Sep 17 00:00:00 2001 From: Jordan Samouh Date: Fri, 17 Mar 2017 17:37:38 +0100 Subject: [PATCH 33/88] [Serializer] [XML] Ignore Process Instruction --- .../Serializer/Encoder/XmlEncoder.php | 10 ++++- .../Tests/Encoder/XmlEncoderTest.php | 38 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php index 0bd85b0247961..40f61167b3698 100644 --- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php @@ -92,14 +92,16 @@ public function decode($data, $format, array $context = array()) throw new UnexpectedValueException($error->message); } + $rootNode = null; foreach ($dom->childNodes as $child) { if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { throw new UnexpectedValueException('Document types are not allowed.'); } + if (!$rootNode && $child->nodeType !== XML_PI_NODE) { + $rootNode = $child; + } } - $rootNode = $dom->firstChild; - // todo: throw an exception if the root node name is not correctly configured (bc) if ($rootNode->hasChildNodes()) { @@ -329,6 +331,10 @@ private function parseXmlValue(\DOMNode $node) $value = array(); foreach ($node->childNodes as $subnode) { + if ($subnode->nodeType === XML_PI_NODE) { + continue; + } + $val = $this->parseXml($subnode); if ('item' === $subnode->nodeName && isset($val['@key'])) { diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 4e83f3464f200..a3c912e7ee6c0 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -371,6 +371,44 @@ public function testDecodeArray() $this->assertEquals($expected, $this->encoder->decode($source, 'xml')); } + public function testDecodeXMLWithProcessInstruction() + { + $source = <<<'XML' + + + + + + foo + + a + b + + val + val + bar + + title1 + + + + title2 + + + + Ed + + + + 1 + + ?> +XML; + $obj = $this->getObject(); + + $this->assertEquals(get_object_vars($obj), $this->encoder->decode($source, 'xml')); + } + public function testDecodeIgnoreWhiteSpace() { $source = <<<'XML' From 067ab52ba09cdb8ab29535b1f4a9885ad52a30d1 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Tue, 21 Mar 2017 18:52:14 +0100 Subject: [PATCH 34/88] HttpCache: New test for revalidating responses with an expired TTL --- .../Tests/HttpCache/HttpCacheTest.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index b6164dd6782fb..985549d13df33 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -809,6 +809,42 @@ public function testValidatesCachedResponsesWithETagAndNoFreshnessInformation() $this->assertTraceNotContains('miss'); } + public function testServesResponseWhileFreshAndRevalidatesWithLastModifiedInformation() + { + $time = \DateTime::createFromFormat('U', time()); + + $this->setNextResponse(200, array(), 'Hello World', function (Request $request, Response $response) use ($time) { + $response->setSharedMaxAge(10); + $response->headers->set('Last-Modified', $time->format(DATE_RFC2822)); + }); + + // prime the cache + $this->request('GET', '/'); + + // next request before s-maxage has expired: Serve from cache + // without hitting the backend + $this->request('GET', '/'); + $this->assertHttpKernelIsNotCalled(); + $this->assertEquals(200, $this->response->getStatusCode()); + $this->assertEquals('Hello World', $this->response->getContent()); + $this->assertTraceContains('fresh'); + + sleep(15); // expire the cache + + $that = $this; + + $this->setNextResponse(304, array(), '', function (Request $request, Response $response) use ($time, $that) { + $that->assertEquals($time->format(DATE_RFC2822), $request->headers->get('IF_MODIFIED_SINCE')); + }); + + $this->request('GET', '/'); + $this->assertHttpKernelIsCalled(); + $this->assertEquals(200, $this->response->getStatusCode()); + $this->assertEquals('Hello World', $this->response->getContent()); + $this->assertTraceContains('stale'); + $this->assertTraceContains('valid'); + } + public function testReplacesCachedResponsesWhenValidationResultsInNon304Response() { $time = \DateTime::createFromFormat('U', time()); From 7d76227e06fcd2cd0b124385c5281442abc16091 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 21 Mar 2017 15:48:22 -0700 Subject: [PATCH 35/88] removed usage of $that --- .../Command/CacheClearCommand/CacheClearCommandTest.php | 5 ++--- .../Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php index ba969c64ae1f4..fd3b611202252 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php @@ -57,11 +57,10 @@ public function testCacheIsFreshAfterCacheClearedWithWarmup() // simply check that cache is warmed up $this->assertGreaterThanOrEqual(1, count($metaFiles)); $configCacheFactory = new ConfigCacheFactory(true); - $that = $this; foreach ($metaFiles as $file) { - $configCacheFactory->cache(substr($file, 0, -5), function () use ($that, $file) { - $that->fail(sprintf('Meta file "%s" is not fresh', (string) $file)); + $configCacheFactory->cache(substr($file, 0, -5), function () use ($file) { + $this->fail(sprintf('Meta file "%s" is not fresh', (string) $file)); }); } diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index 07715e6e12004..f303ec37328d6 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -871,10 +871,8 @@ public function testServesResponseWhileFreshAndRevalidatesWithLastModifiedInform sleep(15); // expire the cache - $that = $this; - - $this->setNextResponse(304, array(), '', function (Request $request, Response $response) use ($time, $that) { - $that->assertEquals($time->format(DATE_RFC2822), $request->headers->get('IF_MODIFIED_SINCE')); + $this->setNextResponse(304, array(), '', function (Request $request, Response $response) use ($time) { + $this->assertEquals($time->format(DATE_RFC2822), $request->headers->get('IF_MODIFIED_SINCE')); }); $this->request('GET', '/'); From 40a67c9e6081294478e2bc45bdff228fa74c1b72 Mon Sep 17 00:00:00 2001 From: Romain Date: Wed, 22 Mar 2017 10:39:50 +0100 Subject: [PATCH 36/88] [WebProfilerBundle] Remove uneeded directive in the form collector styles --- .../WebProfilerBundle/Resources/views/Collector/form.html.twig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig index a59982ce8a9e8..fc4aada9ef3e2 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig @@ -60,7 +60,6 @@ } #tree-menu .empty { border: 0; - margin: 0; padding: 0; } #tree-details-container { From 4bd2c22871538fd056f57033c1284a66f0dbfecb Mon Sep 17 00:00:00 2001 From: Claudio Zizza Date: Sun, 8 Jan 2017 21:17:12 +0100 Subject: [PATCH 37/88] [Validator] Add object handling of invalid constraints in Composite --- .../Component/Validator/Constraints/Composite.php | 4 ++++ .../Validator/Tests/Constraints/CompositeTest.php | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/Symfony/Component/Validator/Constraints/Composite.php b/src/Symfony/Component/Validator/Constraints/Composite.php index ab8466bcfcbc4..d1391bb0724af 100644 --- a/src/Symfony/Component/Validator/Constraints/Composite.php +++ b/src/Symfony/Component/Validator/Constraints/Composite.php @@ -67,6 +67,10 @@ public function __construct($options = null) foreach ($nestedConstraints as $constraint) { if (!$constraint instanceof Constraint) { + if (is_object($constraint)) { + $constraint = get_class($constraint); + } + throw new ConstraintDefinitionException(sprintf('The value %s is not an instance of Constraint in constraint %s', $constraint, get_class($this))); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php index 6a8530723fb05..df4255007c5ca 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php @@ -125,6 +125,17 @@ public function testFailIfNoConstraint() )); } + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + */ + public function testFailIfNoConstraintObject() + { + new ConcreteComposite(array( + new NotNull(array('groups' => 'Default')), + new \ArrayObject(), + )); + } + /** * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException */ From 04caacb757783b2169d799dd6aad8acdca1fb8cf Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 12 Feb 2017 12:31:06 +0100 Subject: [PATCH 38/88] [HttpFoundation] Fix missing handling of for/host/proto info from "Forwarded" header --- .../Component/HttpFoundation/Request.php | 123 ++++++++++-------- .../HttpFoundation/Tests/RequestTest.php | 51 +++++++- .../ValidateRequestListenerTest.php | 2 +- .../HttpKernel/Tests/HttpKernelTest.php | 2 +- 4 files changed, 120 insertions(+), 58 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 81eaf408d49a3..d8bf2ad14baa2 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -206,6 +206,15 @@ class Request protected static $requestFactory; + private $isForwardedValid = true; + + private static $forwardedParams = array( + self::HEADER_CLIENT_IP => 'for', + self::HEADER_CLIENT_HOST => 'host', + self::HEADER_CLIENT_PROTO => 'proto', + self::HEADER_CLIENT_PORT => 'host', + ); + /** * Constructor. * @@ -806,41 +815,13 @@ public function setSession(SessionInterface $session) */ public function getClientIps() { - $clientIps = array(); $ip = $this->server->get('REMOTE_ADDR'); if (!$this->isFromTrustedProxy()) { return array($ip); } - $hasTrustedForwardedHeader = self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED]); - $hasTrustedClientIpHeader = self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP]); - - if ($hasTrustedForwardedHeader) { - $forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]); - preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches); - $forwardedClientIps = $matches[3]; - - $forwardedClientIps = $this->normalizeAndFilterClientIps($forwardedClientIps, $ip); - $clientIps = $forwardedClientIps; - } - - if ($hasTrustedClientIpHeader) { - $xForwardedForClientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP]))); - - $xForwardedForClientIps = $this->normalizeAndFilterClientIps($xForwardedForClientIps, $ip); - $clientIps = $xForwardedForClientIps; - } - - if ($hasTrustedForwardedHeader && $hasTrustedClientIpHeader && $forwardedClientIps !== $xForwardedForClientIps) { - throw new ConflictingHeadersException('The request has both a trusted Forwarded header and a trusted Client IP header, conflicting with each other with regards to the originating IP addresses of the request. This is the result of a misconfiguration. You should either configure your proxy only to send one of these headers, or configure Symfony to distrust one of them.'); - } - - if (!$hasTrustedForwardedHeader && !$hasTrustedClientIpHeader) { - return $this->normalizeAndFilterClientIps(array(), $ip); - } - - return $clientIps; + return $this->getTrustedValues(self::HEADER_CLIENT_IP, $ip) ?: array($ip); } /** @@ -966,31 +947,25 @@ public function getScheme() */ public function getPort() { - if ($this->isFromTrustedProxy()) { - if (self::$trustedHeaders[self::HEADER_CLIENT_PORT] && $port = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PORT])) { - return (int) $port; - } - - if (self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && 'https' === $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO], 'http')) { - return 443; - } + if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_PORT)) { + $host = $host[0]; + } elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) { + $host = $host[0]; + } elseif (!$host = $this->headers->get('HOST')) { + return $this->server->get('SERVER_PORT'); } - if ($host = $this->headers->get('HOST')) { - if ($host[0] === '[') { - $pos = strpos($host, ':', strrpos($host, ']')); - } else { - $pos = strrpos($host, ':'); - } - - if (false !== $pos) { - return (int) substr($host, $pos + 1); - } + if ($host[0] === '[') { + $pos = strpos($host, ':', strrpos($host, ']')); + } else { + $pos = strrpos($host, ':'); + } - return 'https' === $this->getScheme() ? 443 : 80; + if (false !== $pos) { + return (int) substr($host, $pos + 1); } - return $this->server->get('SERVER_PORT'); + return 'https' === $this->getScheme() ? 443 : 80; } /** @@ -1190,8 +1165,8 @@ public function getQueryString() */ public function isSecure() { - if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) { - return in_array(strtolower(current(explode(',', $proto))), array('https', 'on', 'ssl', '1')); + if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_CLIENT_PROTO)) { + return in_array(strtolower($proto[0]), array('https', 'on', 'ssl', '1'), true); } $https = $this->server->get('HTTPS'); @@ -1216,10 +1191,8 @@ public function isSecure() */ public function getHost() { - if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_HOST] && $host = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_HOST])) { - $elements = explode(',', $host, 2); - - $host = $elements[0]; + if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) { + $host = $host[0]; } elseif (!$host = $this->headers->get('HOST')) { if (!$host = $this->server->get('SERVER_NAME')) { $host = $this->server->get('SERVER_ADDR', ''); @@ -1948,8 +1921,48 @@ private function isFromTrustedProxy() return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies); } + private function getTrustedValues($type, $ip = null) + { + $clientValues = array(); + $forwardedValues = array(); + + if (self::$trustedHeaders[$type] && $this->headers->has(self::$trustedHeaders[$type])) { + foreach (explode(',', $this->headers->get(self::$trustedHeaders[$type])) as $v) { + $clientValues[] = (self::HEADER_CLIENT_PORT === $type ? '0.0.0.0:' : '').trim($v); + } + } + + if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) { + $forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]); + $forwardedValues = preg_match_all(sprintf('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array(); + } + + if (null !== $ip) { + $clientValues = $this->normalizeAndFilterClientIps($clientValues, $ip); + $forwardedValues = $this->normalizeAndFilterClientIps($forwardedValues, $ip); + } + + if ($forwardedValues === $clientValues || !$clientValues) { + return $forwardedValues; + } + + if (!$forwardedValues) { + return $clientValues; + } + + if (!$this->isForwardedValid) { + return null !== $ip ? array('0.0.0.0', $ip) : array(); + } + $this->isForwardedValid = false; + + throw new ConflictingHeadersException(sprintf('The request has both a trusted "%s" header and a trusted "%s" header, conflicting with each other. You should either configure your proxy to remove one of them, or configure your project to distrust the offending one.', self::$trustedHeaders[self::HEADER_FORWARDED], self::$trustedHeaders[$type])); + } + private function normalizeAndFilterClientIps(array $clientIps, $ip) { + if (!$clientIps) { + return array(); + } $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from $firstTrustedIp = null; diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index ee753dc6b0778..5687cc62e103c 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1631,7 +1631,7 @@ private function getRequestInstanceForClientIpsForwardedTests($remoteAddr, $http return $request; } - public function testTrustedProxies() + public function testTrustedProxiesXForwardedFor() { $request = Request::create('http://example.com/'); $request->server->set('REMOTE_ADDR', '3.3.3.3'); @@ -1714,6 +1714,55 @@ public function testTrustedProxies() Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO'); } + public function testTrustedProxiesForwarded() + { + $request = Request::create('http://example.com/'); + $request->server->set('REMOTE_ADDR', '3.3.3.3'); + $request->headers->set('FORWARDED', 'for=1.1.1.1, host=foo.example.com:8080, proto=https, for=2.2.2.2, host=real.example.com:8080'); + + // no trusted proxies + $this->assertEquals('3.3.3.3', $request->getClientIp()); + $this->assertEquals('example.com', $request->getHost()); + $this->assertEquals(80, $request->getPort()); + $this->assertFalse($request->isSecure()); + + // disabling proxy trusting + Request::setTrustedProxies(array()); + $this->assertEquals('3.3.3.3', $request->getClientIp()); + $this->assertEquals('example.com', $request->getHost()); + $this->assertEquals(80, $request->getPort()); + $this->assertFalse($request->isSecure()); + + // request is forwarded by a non-trusted proxy + Request::setTrustedProxies(array('2.2.2.2')); + $this->assertEquals('3.3.3.3', $request->getClientIp()); + $this->assertEquals('example.com', $request->getHost()); + $this->assertEquals(80, $request->getPort()); + $this->assertFalse($request->isSecure()); + + // trusted proxy via setTrustedProxies() + Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2')); + $this->assertEquals('1.1.1.1', $request->getClientIp()); + $this->assertEquals('foo.example.com', $request->getHost()); + $this->assertEquals(8080, $request->getPort()); + $this->assertTrue($request->isSecure()); + + // trusted proxy via setTrustedProxies() + Request::setTrustedProxies(array('3.3.3.4', '2.2.2.2')); + $this->assertEquals('3.3.3.3', $request->getClientIp()); + $this->assertEquals('example.com', $request->getHost()); + $this->assertEquals(80, $request->getPort()); + $this->assertFalse($request->isSecure()); + + // check various X_FORWARDED_PROTO header values + Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2')); + $request->headers->set('FORWARDED', 'proto=ssl'); + $this->assertTrue($request->isSecure()); + + $request->headers->set('FORWARDED', 'proto=https, proto=http'); + $this->assertTrue($request->isSecure()); + } + /** * @expectedException \InvalidArgumentException */ diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php index 8311a76e35a03..55dc59e13f716 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php @@ -32,7 +32,7 @@ public function testListenerThrowsWhenMasterRequestHasInconsistentClientIps() $request = new Request(); $request->setTrustedProxies(array('1.1.1.1')); $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('FORWARDED', '2.2.2.2'); + $request->headers->set('FORWARDED', 'for=2.2.2.2'); $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); $dispatcher->addListener(KernelEvents::REQUEST, array(new ValidateRequestListener(), 'onKernelRequest')); diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php index 6a5b2331f7134..448dc10cf1185 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php @@ -287,7 +287,7 @@ public function testInconsistentClientIpsOnMasterRequests() $request = new Request(); $request->setTrustedProxies(array('1.1.1.1')); $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('FORWARDED', '2.2.2.2'); + $request->headers->set('FORWARDED', 'for=2.2.2.2'); $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); $kernel->handle($request, $kernel::MASTER_REQUEST, false); From 43297b45dee44f888d58a3077227a993cf68b930 Mon Sep 17 00:00:00 2001 From: "Anton A. Sumin" Date: Fri, 10 Mar 2017 23:00:21 +0300 Subject: [PATCH 39/88] Fixed pathinfo calculation for requests starting with a question mark. --- .../Component/HttpFoundation/Request.php | 8 ++- .../HttpFoundation/Tests/RequestTest.php | 61 +++++++++++++++++++ .../Security/Http/Tests/HttpUtilsTest.php | 2 +- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index d659d188ea402..69c47a0d540e4 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1774,6 +1774,9 @@ protected function prepareBaseUrl() // Does the baseUrl have anything in common with the request_uri? $requestUri = $this->getRequestUri(); + if ($requestUri !== '' && $requestUri[0] !== '/') { + $requestUri = '/'.$requestUri; + } if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) { // full $baseUrl matches @@ -1846,9 +1849,12 @@ protected function preparePathInfo() } // Remove the query string from REQUEST_URI - if ($pos = strpos($requestUri, '?')) { + if (false !== $pos = strpos($requestUri, '?')) { $requestUri = substr($requestUri, 0, $pos); } + if ($requestUri !== '' && $requestUri[0] !== '/') { + $requestUri = '/'.$requestUri; + } $pathInfo = substr($requestUri, strlen($baseUrl)); if (null !== $baseUrl && (false === $pathInfo || '' === $pathInfo)) { diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 2b852f59565e0..876f40be3b443 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1264,6 +1264,12 @@ public function testGetPathInfo() $request->initialize(array(), array(), array(), array(), array(), $server); $this->assertEquals('/path%20test/info', $request->getPathInfo()); + + $server = array(); + $server['REQUEST_URI'] = '?a=b'; + $request->initialize(array(), array(), array(), array(), array(), $server); + + $this->assertEquals('/', $request->getPathInfo()); } public function testGetPreferredLanguage() @@ -1992,6 +1998,61 @@ public function methodCacheableProvider() array('CONNECT', false), ); } + + public function nonstandardRequestsData() + { + return array( + array('', '', '/', 'http://host:8080/', ''), + array('/', '', '/', 'http://host:8080/', ''), + + array('hello/app.php/x', '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'), + array('/hello/app.php/x', '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'), + + array('', 'a=b', '/', 'http://host:8080/?a=b'), + array('?a=b', 'a=b', '/', 'http://host:8080/?a=b'), + array('/?a=b', 'a=b', '/', 'http://host:8080/?a=b'), + + array('x', 'a=b', '/x', 'http://host:8080/x?a=b'), + array('x?a=b', 'a=b', '/x', 'http://host:8080/x?a=b'), + array('/x?a=b', 'a=b', '/x', 'http://host:8080/x?a=b'), + + array('hello/x', '', '/x', 'http://host:8080/hello/x', '/hello'), + array('/hello/x', '', '/x', 'http://host:8080/hello/x', '/hello'), + + array('hello/app.php/x', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'), + array('hello/app.php/x?a=b', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'), + array('/hello/app.php/x?a=b', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'), + ); + } + + /** + * @dataProvider nonstandardRequestsData + */ + public function testNonstandardRequests($requestUri, $queryString, $expectedPathInfo, $expectedUri, $expectedBasePath = '', $expectedBaseUrl = null) + { + if (null === $expectedBaseUrl) { + $expectedBaseUrl = $expectedBasePath; + } + + $server = array( + 'HTTP_HOST' => 'host:8080', + 'SERVER_PORT' => '8080', + 'QUERY_STRING' => $queryString, + 'PHP_SELF' => '/hello/app.php', + 'SCRIPT_FILENAME' => '/some/path/app.php', + 'REQUEST_URI' => $requestUri, + ); + + $request = new Request(array(), array(), array(), array(), array(), $server); + + $this->assertEquals($expectedPathInfo, $request->getPathInfo()); + $this->assertEquals($expectedUri, $request->getUri()); + $this->assertEquals($queryString, $request->getQueryString()); + $this->assertEquals(8080, $request->getPort()); + $this->assertEquals('host:8080', $request->getHttpHost()); + $this->assertEquals($expectedBaseUrl, $request->getBaseUrl()); + $this->assertEquals($expectedBasePath, $request->getBasePath()); + } } class RequestContentProxy extends Request diff --git a/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php b/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php index eb0379f97b4f5..3d0e63b6fe1b9 100644 --- a/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php +++ b/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php @@ -144,7 +144,7 @@ public function testCheckRequestPath() // Plus must not decoded to space $this->assertTrue($utils->checkRequestPath($this->getRequest('/foo+bar'), '/foo+bar')); // Checking unicode - $this->assertTrue($utils->checkRequestPath($this->getRequest(urlencode('/вход')), '/вход')); + $this->assertTrue($utils->checkRequestPath($this->getRequest('/'.urlencode('вход')), '/вход')); } public function testCheckRequestPathWithUrlMatcherAndResourceNotFound() From 3599c476bf0638d7df5f99232cd570aed2baee0c Mon Sep 17 00:00:00 2001 From: Nikolay Labinskiy Date: Thu, 16 Mar 2017 13:01:13 +0200 Subject: [PATCH 40/88] [Validator] fix URL validator to detect non supported chars according to RFC 3986 --- src/Symfony/Component/Validator/Constraints/UrlValidator.php | 4 +++- .../Validator/Tests/Constraints/UrlValidatorTest.php | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 401f7d8bdd648..db7244f40ce7b 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -34,7 +34,9 @@ class UrlValidator extends ConstraintValidator \] # an IPv6 address ) (:[0-9]+)? # a port (optional) - (/?|/\S+|\?\S*|\#\S*) # a /, nothing, a / with something, a query or a fragment + (?:/ (?:[\pL\pN\-._\~!$&\'()*+,;=:@]|%%[0-9A-Fa-f]{2})* )* # a path + (?:\? (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )? # a query (optional) + (?:\# (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )? # a fragment (optional) $~ixu'; /** diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index 98494c66bf361..39f1708cf18ad 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -128,6 +128,7 @@ public function getValidUrls() array('http://symfony.com#'), array('http://symfony.com#fragment'), array('http://symfony.com/#fragment'), + array('http://symfony.com/#one_more%20test'), ); } @@ -167,6 +168,9 @@ public function getInvalidUrls() array('http://:password@@symfony.com'), array('http://username:passwordsymfony.com'), array('http://usern@me:password@symfony.com'), + array('http://example.com/exploit.html?'), + array('http://example.com/exploit.html?hel lo'), + array('http://example.com/exploit.html?not_a%hex'), ); } From 3a7fa7ede265d4e2d06c8c4030a1c6ddd8168669 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 17 Mar 2017 12:57:37 +0100 Subject: [PATCH 41/88] Set Date header in Response constructor already --- src/Symfony/Component/HttpFoundation/Response.php | 11 +++++++++++ .../Component/HttpFoundation/Tests/ResponseTest.php | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index 9d112d15785d0..3eb8bd289ce05 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -201,6 +201,11 @@ public function __construct($content = '', $status = 200, $headers = array()) $this->setContent($content); $this->setStatusCode($status); $this->setProtocolVersion('1.0'); + + /* RFC2616 - 14.18 says all Responses need to have a Date */ + if (!$this->headers->has('Date')) { + $this->setDate(new \DateTime(null, new \DateTimeZone('UTC'))); + } } /** @@ -329,6 +334,7 @@ public function sendHeaders() return $this; } + /* RFC2616 - 14.18 says all Responses need to have a Date */ if (!$this->headers->has('Date')) { $this->setDate(\DateTime::createFromFormat('U', time())); } @@ -612,6 +618,11 @@ public function mustRevalidate() */ public function getDate() { + /* + RFC2616 - 14.18 says all Responses need to have a Date. + Make sure we provide one even if it the header + has been removed in the meantime. + */ if (!$this->headers->has('Date')) { $this->setDate(\DateTime::createFromFormat('U', time())); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php index d73dd3d344c3f..453a05a9b022e 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php @@ -276,8 +276,10 @@ public function testGetDate() $this->assertEquals($now->getTimestamp(), $date->getTimestamp(), '->getDate() returns the date when the header has been modified'); $response = new Response('', 200); + $now = $this->createDateTimeNow(); $response->headers->remove('Date'); - $this->assertInstanceOf('\DateTime', $response->getDate()); + $date = $response->getDate(); + $this->assertEquals($now->getTimestamp(), $date->getTimestamp(), '->getDate() returns the current Date when the header has previously been removed'); } public function testGetMaxAge() From d980e706ad43801c5edb2bca52876c12a99934b8 Mon Sep 17 00:00:00 2001 From: Nikolay Labinskiy Date: Thu, 23 Mar 2017 11:17:21 +0200 Subject: [PATCH 42/88] [WebProfilerBundle] Fix for CSS attribute at Profiler Translation Page --- .../Resources/views/Collector/translation.html.twig | 6 +++--- .../Resources/views/Profiler/profiler.css.twig | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig index 0be04e76117d8..da55ef9190323 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig @@ -169,10 +169,10 @@ {% for message in messages %} {{ message.locale }} - {{ message.domain }} + {{ message.domain }} {{ message.count }} - {{ message.id }} + {{ message.id }} {% if message.transChoiceNumber is not null %} (pluralization is used) @@ -189,7 +189,7 @@
{% endif %} - {{ message.translation }} + {{ message.translation }} {% endfor %} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig index b807d0bcf9b5b..e36c7fdad1e2b 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig @@ -197,6 +197,9 @@ table tbody ul { .nowrap { white-space: pre; } +.prewrap { + white-space: pre-wrap; +} .newline { display: block; } From 6d23c8c41cb4bdc002e5501bc65e3c34f51780e8 Mon Sep 17 00:00:00 2001 From: Antanas Arvasevicius Date: Wed, 1 Mar 2017 14:16:35 +0200 Subject: [PATCH 43/88] #21809 [SecurityBundle] bugfix: if security provider's name contains upper cases then container didn't compile --- .../DependencyInjection/SecurityExtension.php | 6 ++-- .../app/CamelCasedProviders/bundles.php | 16 ++++++++++ .../app/CamelCasedProviders/config.yml | 30 +++++++++++++++++++ ...amelCasedProvidersCausesExceptionsTest.php | 20 +++++++++++++ 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/bundles.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProvidersCausesExceptionsTest.php diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 36c16e0dbc7d9..2fd12c9436c39 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -509,7 +509,7 @@ private function createUserProviders($config, ContainerBuilder $container) // Parses a tag and returns the id for the related user provider service private function createUserDaoProvider($name, $provider, ContainerBuilder $container) { - $name = $this->getUserProviderId(strtolower($name)); + $name = $this->getUserProviderId($name); // Doctrine Entity and In-memory DAO provider are managed by factories foreach ($this->userProviderFactories as $factory) { @@ -533,7 +533,7 @@ private function createUserDaoProvider($name, $provider, ContainerBuilder $conta if (isset($provider['chain'])) { $providers = array(); foreach ($provider['chain']['providers'] as $providerName) { - $providers[] = new Reference($this->getUserProviderId(strtolower($providerName))); + $providers[] = new Reference($this->getUserProviderId($providerName)); } $container @@ -548,7 +548,7 @@ private function createUserDaoProvider($name, $provider, ContainerBuilder $conta private function getUserProviderId($name) { - return 'security.user.provider.concrete.'.$name; + return 'security.user.provider.concrete.'.strtolower($name); } private function createExceptionListener($container, $config, $id, $defaultEntryPoint, $stateless) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/bundles.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/bundles.php new file mode 100644 index 0000000000000..86614bdb891de --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/bundles.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return array( + new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), + new Symfony\Bundle\SecurityBundle\SecurityBundle(), + new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), +); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml new file mode 100644 index 0000000000000..0b21534ecf420 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml @@ -0,0 +1,30 @@ +imports: + - { resource: ./../config/framework.yml } + +doctrine: + dbal: + driver: pdo_sqlite + memory: true + charset: UTF8 + + orm: + entity_managers: + default: + + auto_mapping: true + +security: + providers: + camelCasedName: + entity: + class: Symfony\Component\Security\Core\User\User + + firewalls: + default: + anonymous: ~ + provider: camelCasedName + + encoders: + Symfony\Component\Security\Core\User\User: plaintext + + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProvidersCausesExceptionsTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProvidersCausesExceptionsTest.php new file mode 100644 index 0000000000000..41db3338da97d --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProvidersCausesExceptionsTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Tests\Functional; + +class CamelCasedProvidersCausesExceptionsTest extends WebTestCase +{ + public function testBugfixExceptionThenCamelCasedProviderIsGiven() + { + $client = $this->createClient(array('test_case' => 'CamelCasedProviders', 'root_config' => 'config.yml')); + } +} From e31d3461ea9a50ad7236a023601aac767d3e8868 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 23 Mar 2017 09:02:44 -0700 Subject: [PATCH 44/88] fixed tests --- .../Tests/Functional/app/CamelCasedProviders/config.yml | 1 - src/Symfony/Bundle/SecurityBundle/composer.json | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml index 0b21534ecf420..a2850489edd7a 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml @@ -10,7 +10,6 @@ doctrine: orm: entity_managers: default: - auto_mapping: true security: diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 5251f0138aa56..38bae8b0e0f74 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -37,6 +37,7 @@ "symfony/yaml": "^2.0.5", "symfony/expression-language": "~2.6", "doctrine/doctrine-bundle": "~1.2", + "doctrine/orm": "~2.4,>=2.4.5", "twig/twig": "~1.28|~2.0", "ircmaxell/password-compat": "~1.0" }, From 80af0838f5170a3f7738d69a549dc48073d005c2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 23 Mar 2017 09:07:15 -0700 Subject: [PATCH 45/88] removed test that does not test anything --- .../app/CamelCasedProviders/bundles.php | 16 ---------- .../app/CamelCasedProviders/config.yml | 29 ------------------- ...amelCasedProvidersCausesExceptionsTest.php | 20 ------------- .../Bundle/SecurityBundle/composer.json | 1 - 4 files changed, 66 deletions(-) delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/bundles.php delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProvidersCausesExceptionsTest.php diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/bundles.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/bundles.php deleted file mode 100644 index 86614bdb891de..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/bundles.php +++ /dev/null @@ -1,16 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -return array( - new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), - new Symfony\Bundle\SecurityBundle\SecurityBundle(), - new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), -); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml deleted file mode 100644 index a2850489edd7a..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProviders/config.yml +++ /dev/null @@ -1,29 +0,0 @@ -imports: - - { resource: ./../config/framework.yml } - -doctrine: - dbal: - driver: pdo_sqlite - memory: true - charset: UTF8 - - orm: - entity_managers: - default: - auto_mapping: true - -security: - providers: - camelCasedName: - entity: - class: Symfony\Component\Security\Core\User\User - - firewalls: - default: - anonymous: ~ - provider: camelCasedName - - encoders: - Symfony\Component\Security\Core\User\User: plaintext - - diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProvidersCausesExceptionsTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProvidersCausesExceptionsTest.php deleted file mode 100644 index 41db3338da97d..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/CamelCasedProvidersCausesExceptionsTest.php +++ /dev/null @@ -1,20 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\SecurityBundle\Tests\Functional; - -class CamelCasedProvidersCausesExceptionsTest extends WebTestCase -{ - public function testBugfixExceptionThenCamelCasedProviderIsGiven() - { - $client = $this->createClient(array('test_case' => 'CamelCasedProviders', 'root_config' => 'config.yml')); - } -} diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 38bae8b0e0f74..5251f0138aa56 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -37,7 +37,6 @@ "symfony/yaml": "^2.0.5", "symfony/expression-language": "~2.6", "doctrine/doctrine-bundle": "~1.2", - "doctrine/orm": "~2.4,>=2.4.5", "twig/twig": "~1.28|~2.0", "ircmaxell/password-compat": "~1.0" }, From d50ffa1de7e0474024147b68b69db9b036d5b70d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 21 Mar 2017 09:40:59 +0100 Subject: [PATCH 46/88] normalize paths before making them relative --- .../Component/Filesystem/Filesystem.php | 25 +++++++++++++++++++ .../Filesystem/Tests/FilesystemTest.php | 10 ++++++++ 2 files changed, 35 insertions(+) diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 3a5e332b9ecef..edfc1b9d46a23 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -362,6 +362,31 @@ public function makePathRelative($endPath, $startPath) $startPathArr = explode('/', trim($startPath, '/')); $endPathArr = explode('/', trim($endPath, '/')); + if ('/' !== $startPath[0]) { + array_shift($startPathArr); + } + + if ('/' !== $endPath[0]) { + array_shift($endPathArr); + } + + $normalizePathArray = function ($pathSegments) { + $result = array(); + + foreach ($pathSegments as $segment) { + if ('..' === $segment) { + array_pop($result); + } else { + $result[] = $segment; + } + } + + return $result; + }; + + $startPathArr = $normalizePathArray($startPathArr); + $endPathArr = $normalizePathArray($endPathArr); + // Find for which directory the common path stops $index = 0; while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) { diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index be47a2d0ce724..ab2395cd001c0 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -868,6 +868,16 @@ public function providePathsForMakePathRelative() array('/a/aab/bb/', '/b/aab', '../../a/aab/bb/'), array('/aab/bb', '/aa', '../aab/bb/'), array('/aab', '/aa', '../aab/'), + array('/aa/bb/cc', '/aa/dd/..', 'bb/cc/'), + array('/aa/../bb/cc', '/aa/dd/..', '../bb/cc/'), + array('/aa/bb/../../cc', '/aa/../dd/..', 'cc/'), + array('/../aa/bb/cc', '/aa/dd/..', 'bb/cc/'), + array('/../../aa/../bb/cc', '/aa/dd/..', '../bb/cc/'), + array('C:/aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'), + array('c:/aa/../bb/cc', 'c:/aa/dd/..', '../bb/cc/'), + array('C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'), + array('C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'), + array('C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'), ); if ('\\' === DIRECTORY_SEPARATOR) { From ef39b704ccbdd6680c71d2d3841c0a8e6277d3ce Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Fri, 24 Mar 2017 10:02:28 +0100 Subject: [PATCH 47/88] [Form] Improve the exceptions when trying to get the data in a PRE_SET_DATA listener and the data has not already been set --- src/Symfony/Component/Form/Form.php | 12 +++++ .../Component/Form/Tests/SimpleFormTest.php | 46 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 54b9b39ebd02c..87cd15bf47d87 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -408,6 +408,10 @@ public function getData() } if (!$this->defaultDataSet) { + if ($this->lockSetData) { + throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call getData() if the form data has not already been set. You should call getData() on the FormEvent object instead.'); + } + $this->setData($this->config->getData()); } @@ -428,6 +432,10 @@ public function getNormData() } if (!$this->defaultDataSet) { + if ($this->lockSetData) { + throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call getNormData() if the form data has not already been set.'); + } + $this->setData($this->config->getData()); } @@ -448,6 +456,10 @@ public function getViewData() } if (!$this->defaultDataSet) { + if ($this->lockSetData) { + throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call getViewData() if the form data has not already been set.'); + } + $this->setData($this->config->getData()); } diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index 6223d3b39f95c..62c94c7490cee 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -903,6 +903,7 @@ public function testViewDataMustBeObjectIfDataClassIsSet() /** * @expectedException \Symfony\Component\Form\Exception\RuntimeException + * @expectedExceptionMessage A cycle was detected. Listeners to the PRE_SET_DATA event must not call setData(). You should call setData() on the FormEvent object instead. */ public function testSetDataCannotInvokeItself() { @@ -1084,6 +1085,51 @@ public function testCustomOptionsResolver() $fooType->setDefaultOptions($resolver); } + /** + * @expectedException \Symfony\Component\Form\Exception\RuntimeException + * @expectedExceptionMessage A cycle was detected. Listeners to the PRE_SET_DATA event must not call getData() if the form data has not already been set. You should call getData() on the FormEvent object instead. + */ + public function testCannotCallGetDataInPreSetDataListenerIfDataHasNotAlreadyBeenSet() + { + $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); + $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $event->getForm()->getData(); + }); + $form = new Form($config); + + $form->setData('foo'); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\RuntimeException + * @expectedExceptionMessage A cycle was detected. Listeners to the PRE_SET_DATA event must not call getNormData() if the form data has not already been set. + */ + public function testCannotCallGetNormDataInPreSetDataListener() + { + $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); + $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $event->getForm()->getNormData(); + }); + $form = new Form($config); + + $form->setData('foo'); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\RuntimeException + * @expectedExceptionMessage A cycle was detected. Listeners to the PRE_SET_DATA event must not call getViewData() if the form data has not already been set. + */ + public function testCannotCallGetViewDataInPreSetDataListener() + { + $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); + $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + $event->getForm()->getViewData(); + }); + $form = new Form($config); + + $form->setData('foo'); + } + protected function createForm() { return $this->getBuilder()->getForm(); From 967f7a7add84628ac3301a892e920b32aa3488bd Mon Sep 17 00:00:00 2001 From: Dawid Nowak Date: Fri, 24 Mar 2017 04:23:13 +0100 Subject: [PATCH 48/88] MockArraySessionStorage: updated phpdoc for $bags so that IDE autocompletion would work --- .../HttpFoundation/Session/Storage/MockArraySessionStorage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php index c26cc1334d6aa..c932d4003f1aa 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php @@ -58,7 +58,7 @@ class MockArraySessionStorage implements SessionStorageInterface protected $metadataBag; /** - * @var array + * @var array|SessionBagInterface[] */ protected $bags; From d984c73e66ec5bd5ecfe46d62e5f0d9fd732a179 Mon Sep 17 00:00:00 2001 From: Dawid Nowak Date: Fri, 24 Mar 2017 04:07:57 +0100 Subject: [PATCH 49/88] [HttpFoundation][bugfix] should always be initialized --- .../Storage/MockArraySessionStorage.php | 2 +- .../Storage/MockArraySessionStorageTest.php | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php index c26cc1334d6aa..78404d7b4405b 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php @@ -60,7 +60,7 @@ class MockArraySessionStorage implements SessionStorageInterface /** * @var array */ - protected $bags; + protected $bags = array(); /** * Constructor. diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MockArraySessionStorageTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MockArraySessionStorageTest.php index 99da778b5fd87..82df5543eb540 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MockArraySessionStorageTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MockArraySessionStorageTest.php @@ -97,6 +97,30 @@ public function testGetId() $this->assertNotEquals('', $this->storage->getId()); } + public function testClearClearsBags() + { + $this->storage->clear(); + + $this->assertSame(array(), $this->storage->getBag('attributes')->all()); + $this->assertSame(array(), $this->storage->getBag('flashes')->peekAll()); + } + + public function testClearStartsSession() + { + $this->storage->clear(); + + $this->assertTrue($this->storage->isStarted()); + } + + public function testClearWithNoBagsStartsSession() + { + $storage = new MockArraySessionStorage(); + + $storage->clear(); + + $this->assertTrue($storage->isStarted()); + } + /** * @expectedException \RuntimeException */ From cb1348231a2378ff8af5e69c93e81bf3089bb52f Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 24 Mar 2017 09:57:35 +0100 Subject: [PATCH 50/88] [Console] Escape exception messages --- src/Symfony/Component/Console/Application.php | 3 ++- .../Fixtures/application_renderexception3.txt | 16 ++++++++-------- .../application_renderexception3decorated.txt | 18 +++++++++--------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index a9351a589720c..32bd8373db221 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -13,6 +13,7 @@ use Symfony\Component\Console\Descriptor\TextDescriptor; use Symfony\Component\Console\Descriptor\XmlDescriptor; +use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\DebugFormatterHelper; use Symfony\Component\Console\Helper\ProcessHelper; use Symfony\Component\Console\Helper\QuestionHelper; @@ -651,7 +652,7 @@ public function renderException($e, $output) } $formatter = $output->getFormatter(); $lines = array(); - foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) { + foreach (preg_split('/\r?\n/', OutputFormatter::escape($e->getMessage())) as $line) { foreach ($this->splitStringByWidth($line, $width - 4) as $line) { // pre-format lines to get the right string length $lineLength = $this->stringWidth(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt index 8276137bd886a..f41925f52a6ea 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3.txt @@ -1,13 +1,13 @@ - - [Exception] - Third exception comment - + + [Exception] + Third exception comment + - - [Exception] - Second exception comment - + + [Exception] + Second exception comment + [Exception] diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3decorated.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3decorated.txt index b4a7b018af377..5adccdd70245f 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3decorated.txt +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception3decorated.txt @@ -1,17 +1,17 @@ -  - [Exception]  - Third exception comment  -  +  + [Exception]  + Third exception comment  +  -  - [Exception]  - Second exception comment  -  +  + [Exception]  + Second exception comment  +     [Exception]  - First exception 

this is html

  + First exception

this is html

   foo3:bar From a61797f8504d03a3981d0d5ad326971a33f17282 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sat, 25 Mar 2017 15:42:26 +0100 Subject: [PATCH 51/88] [FrameworkBundle] Cache pool clear command requires at least 1 pool --- .../Bundle/FrameworkBundle/Command/CachePoolClearCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php index 82934e1845fea..eec7b0d7ea11b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolClearCommand.php @@ -33,7 +33,7 @@ protected function configure() $this ->setName('cache:pool:clear') ->setDefinition(array( - new InputArgument('pools', InputArgument::IS_ARRAY, 'A list of cache pools or cache pool clearers'), + new InputArgument('pools', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'A list of cache pools or cache pool clearers'), )) ->setDescription('Clears cache pools') ->setHelp(<<<'EOF' From 543ac435b8c89dc1161fc8a6c30fcbd93b95f4c2 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sun, 26 Mar 2017 13:49:50 +0200 Subject: [PATCH 52/88] [WebProfilerBundle] Include badge status in translation tabs --- .../Resources/views/Collector/translation.html.twig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig index ef3a32822ad41..31881953d8139 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig @@ -8,7 +8,7 @@ {{ include('@WebProfiler/Icon/translation.svg') }} {% set status_color = collector.countMissings ? 'red' : collector.countFallbacks ? 'yellow' %} {% set error_count = collector.countMissings + collector.countFallbacks %} - {{ error_count ?: collector.countdefines }} + {{ error_count ?: collector.countDefines }} {% endset %} {% set text %} @@ -28,7 +28,7 @@
Defined messages - {{ collector.countdefines }} + {{ collector.countDefines }}
{% endset %} @@ -65,7 +65,7 @@
- {{ collector.countdefines }} + {{ collector.countDefines }} Defined messages
@@ -96,7 +96,7 @@
-

Defined {{ messages_defined|length }}

+

Defined {{ collector.countDefines }}

@@ -114,7 +114,7 @@

-

Fallback {{ messages_fallback|length }}

+

Fallback {{ collector.countFallbacks }}

@@ -133,7 +133,7 @@

-

Missing {{ messages_missing|length }}

+

Missing {{ collector.countMissings }}

From 0577c7b089916bde9243fee8cfd08fc14fad1eac Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 26 Mar 2017 17:08:59 +0200 Subject: [PATCH 53/88] [Bridge\Doctrine] Fix change breaking doctrine-bundle test suite --- ...egisterEventListenersAndSubscribersPass.php | 7 ++----- ...terEventListenersAndSubscribersPassTest.php | 18 +++++++++--------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php index 1ec3ba323b788..cb4a4816db70a 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php @@ -109,15 +109,12 @@ private function addTaggedListeners(ContainerBuilder $container) throw new RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $id, implode(', ', array_keys($this->connections)))); } - if ($lazy = isset($tag['lazy']) && $tag['lazy']) { + if ($lazy = !empty($tag['lazy'])) { $taggedListenerDef->setPublic(true); } // we add one call per event per service so we have the correct order - $this->getEventManagerDef($container, $con)->addMethodCall('addEventListener', array( - $tag['event'], - $lazy ? $id : new Reference($id), - )); + $this->getEventManagerDef($container, $con)->addMethodCall('addEventListener', array(array($tag['event']), $lazy ? $id : new Reference($id))); } } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPassTest.php b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPassTest.php index 6e4eb202984ed..7e99a7d9356c2 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPassTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPassTest.php @@ -90,11 +90,11 @@ public function testProcessEventListenersWithPriorities() $this->assertEquals( array( - array('addEventListener', array('foo_bar', new Reference('c'))), - array('addEventListener', array('foo_bar', new Reference('a'))), - array('addEventListener', array('bar', new Reference('a'))), - array('addEventListener', array('foo', new Reference('b'))), - array('addEventListener', array('foo', new Reference('a'))), + array('addEventListener', array(array('foo_bar'), new Reference('c'))), + array('addEventListener', array(array('foo_bar'), new Reference('a'))), + array('addEventListener', array(array('bar'), new Reference('a'))), + array('addEventListener', array(array('foo'), new Reference('b'))), + array('addEventListener', array(array('foo'), new Reference('a'))), ), $methodCalls ); @@ -138,16 +138,16 @@ public function testProcessEventListenersWithMultipleConnections() $this->assertEquals( array( - array('addEventListener', array('onFlush', new Reference('a'))), - array('addEventListener', array('onFlush', new Reference('b'))), + array('addEventListener', array(array('onFlush'), new Reference('a'))), + array('addEventListener', array(array('onFlush'), new Reference('b'))), ), $container->getDefinition('doctrine.dbal.default_connection.event_manager')->getMethodCalls() ); $this->assertEquals( array( - array('addEventListener', array('onFlush', new Reference('a'))), - array('addEventListener', array('onFlush', new Reference('c'))), + array('addEventListener', array(array('onFlush'), new Reference('a'))), + array('addEventListener', array(array('onFlush'), new Reference('c'))), ), $container->getDefinition('doctrine.dbal.second_connection.event_manager')->getMethodCalls() ); From dbcfa5c65938fb134089aa41ef23079be02afa5f Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Mon, 27 Mar 2017 07:41:37 +0200 Subject: [PATCH 54/88] Remove port from default host in server:status command --- .../Bundle/FrameworkBundle/Command/ServerStatusCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php index fa5c537a0c97a..58871896c651d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php @@ -31,7 +31,7 @@ protected function configure() { $this ->setDefinition(array( - new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'), + new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1'), new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'), )) ->setName('server:status') From ba8f46ad237f7d81d3917406caf5a2b1eabc4eb8 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Mar 2017 16:31:27 +0200 Subject: [PATCH 55/88] [HttpKernel] Fix test --- .../Tests/EventListener/ValidateRequestListenerTest.php | 2 +- src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php index 8311a76e35a03..55dc59e13f716 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php @@ -32,7 +32,7 @@ public function testListenerThrowsWhenMasterRequestHasInconsistentClientIps() $request = new Request(); $request->setTrustedProxies(array('1.1.1.1')); $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('FORWARDED', '2.2.2.2'); + $request->headers->set('FORWARDED', 'for=2.2.2.2'); $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); $dispatcher->addListener(KernelEvents::REQUEST, array(new ValidateRequestListener(), 'onKernelRequest')); diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php index 6a5b2331f7134..448dc10cf1185 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php @@ -287,7 +287,7 @@ public function testInconsistentClientIpsOnMasterRequests() $request = new Request(); $request->setTrustedProxies(array('1.1.1.1')); $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('FORWARDED', '2.2.2.2'); + $request->headers->set('FORWARDED', 'for=2.2.2.2'); $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); $kernel->handle($request, $kernel::MASTER_REQUEST, false); From e9c3df6c94ee2388c7c45cc91e42b71c51bfaf51 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Mar 2017 16:36:46 +0200 Subject: [PATCH 56/88] [Console] Fix test --- .../Component/Console/Tests/Logger/ConsoleLoggerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Tests/Logger/ConsoleLoggerTest.php b/src/Symfony/Component/Console/Tests/Logger/ConsoleLoggerTest.php index cb9f0e8ea1f5f..342992982aa50 100644 --- a/src/Symfony/Component/Console/Tests/Logger/ConsoleLoggerTest.php +++ b/src/Symfony/Component/Console/Tests/Logger/ConsoleLoggerTest.php @@ -70,7 +70,7 @@ public function testOutputMapping($logLevel, $outputVerbosity, $isOutput, $addVe $logger = new ConsoleLogger($out, $addVerbosityLevelMap); $logger->log($logLevel, 'foo bar'); $logs = $out->fetch(); - $this->assertEquals($isOutput ? "[$logLevel] foo bar\n" : '', $logs); + $this->assertEquals($isOutput ? "[$logLevel] foo bar".PHP_EOL : '', $logs); } public function provideOutputMappingParams() From 9439237c8130b6b648e30b8c0506ab8f830558b0 Mon Sep 17 00:00:00 2001 From: Patrick Dawkins Date: Mon, 27 Mar 2017 17:26:57 +0100 Subject: [PATCH 57/88] [Process] Fix bug which wiped or mangled env vars --- src/Symfony/Component/Process/Process.php | 2 +- .../Component/Process/Tests/ProcessTest.php | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 504b4c3bc567d..bd00e1761c574 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -277,7 +277,7 @@ public function start(callable $callback = null) } foreach ($env as $k => $v) { - $envBackup[$k] = getenv($v); + $envBackup[$k] = getenv($k); putenv(false === $v || null === $v ? $k : "$k=$v"); } $env = null; diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index c51a116e7319f..379dae2df717a 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1403,6 +1403,20 @@ public function testSetBadEnv() $this->assertSame('', $process->getErrorOutput()); } + public function testEnvBackupDoesNotDeleteExistingVars() + { + putenv('existing_var=foo'); + $process = $this->getProcess('php -r "echo getenv(\'new_test_var\');"'); + $process->setEnv(array('existing_var' => 'bar', 'new_test_var' => 'foo')); + $process->inheritEnvironmentVariables(); + + $process->run(); + + $this->assertSame('foo', $process->getOutput()); + $this->assertSame('foo', getenv('existing_var')); + $this->assertFalse(getenv('new_test_var')); + } + public function testInheritEnvEnabled() { $process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('echo serialize($_SERVER);'), null, array('BAR' => 'BAZ')); From 3fe419cf66a8a9f033db54186896b142c5cbcada Mon Sep 17 00:00:00 2001 From: Julien Falque Date: Tue, 28 Mar 2017 08:19:43 +0200 Subject: [PATCH 58/88] Disable color support detection for tests --- src/Symfony/Component/Console/Tester/CommandTester.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Symfony/Component/Console/Tester/CommandTester.php b/src/Symfony/Component/Console/Tester/CommandTester.php index f95298bc90c79..609f46a654da9 100644 --- a/src/Symfony/Component/Console/Tester/CommandTester.php +++ b/src/Symfony/Component/Console/Tester/CommandTester.php @@ -70,9 +70,7 @@ public function execute(array $input, array $options = array()) } $this->output = new StreamOutput(fopen('php://memory', 'w', false)); - if (isset($options['decorated'])) { - $this->output->setDecorated($options['decorated']); - } + $this->output->setDecorated(isset($options['decorated']) ? $options['decorated'] : false); if (isset($options['verbosity'])) { $this->output->setVerbosity($options['verbosity']); } From 8f090bca12f3effa76e7bca28a29e1d311174cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 28 Mar 2017 09:52:43 +0200 Subject: [PATCH 59/88] [Workflow] Added more PHPDoc --- .../Twig/Extension/WorkflowExtension.php | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php b/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php index c2c5a55af954f..766420a91d75a 100644 --- a/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php @@ -35,14 +35,31 @@ public function getFunctions() ); } - public function canTransition($object, $transition, $name = null) + /** + * Returns true if the transition is enabled. + * + * @param object $subject A subject + * @param string $transitionName A transition + * @param string $name A workflow name + * + * @return bool true if the transition is enabled + */ + public function canTransition($subject, $transitionName, $name = null) { - return $this->workflowRegistry->get($object, $name)->can($object, $transition); + return $this->workflowRegistry->get($subject, $name)->can($subject, $transitionName); } - public function getEnabledTransitions($object, $name = null) + /** + * Returns all enabled transitions. + * + * @param object $subject A subject + * @param string $name A workflow name + * + * @return Transition[] All enabled transitions + */ + public function getEnabledTransitions($subject, $name = null) { - return $this->workflowRegistry->get($object, $name)->getEnabledTransitions($object); + return $this->workflowRegistry->get($subject, $name)->getEnabledTransitions($subject); } public function getName() From d64679014b5eb6b36594f5d7062ad07f9ef198ab Mon Sep 17 00:00:00 2001 From: Niels Keurentjes Date: Sat, 25 Mar 2017 00:33:11 +0100 Subject: [PATCH 60/88] [WebProfilerBundle] Normalize whitespace in exceptions passed in headers If an exception was thrown with line separators in its message the WebProfiler would cause an exception by passing it through unsanitized into the X-Debug-Error HTTP header. This commit fixes that by replacing all whitespace sequences with a single space in the header. --- .../EventListener/WebDebugToolbarListener.php | 2 +- .../WebDebugToolbarListenerTest.php | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php index 71c5090fc8a53..09d2b9ba92e5d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php +++ b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php @@ -68,7 +68,7 @@ public function onKernelResponse(FilterResponseEvent $event) $this->urlGenerator->generate('_profiler', array('token' => $response->headers->get('X-Debug-Token'))) ); } catch (\Exception $e) { - $response->headers->set('X-Debug-Error', get_class($e).': '.$e->getMessage()); + $response->headers->set('X-Debug-Error', get_class($e).': '.preg_replace('/\s+/', ' ', $e->getMessage())); } } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php index 446aefb793e89..a121035b7d53d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php @@ -228,6 +228,27 @@ public function testThrowingUrlGenerator() $this->assertEquals('Exception: foo', $response->headers->get('X-Debug-Error')); } + public function testThrowingErrorCleanup() + { + $response = new Response(); + $response->headers->set('X-Debug-Token', 'xxxxxxxx'); + + $urlGenerator = $this->getUrlGeneratorMock(); + $urlGenerator + ->expects($this->once()) + ->method('generate') + ->with('_profiler', array('token' => 'xxxxxxxx')) + ->will($this->throwException(new \Exception("This\nmultiline\r\ntabbed text should\tcome out\r on\n \ta single plain\r\nline"))) + ; + + $event = new FilterResponseEvent($this->getKernelMock(), $this->getRequestMock(), HttpKernelInterface::MASTER_REQUEST, $response); + + $listener = new WebDebugToolbarListener($this->getTwigMock(), false, WebDebugToolbarListener::ENABLED, 'bottom', $urlGenerator); + $listener->onKernelResponse($event); + + $this->assertEquals('Exception: This multiline tabbed text should come out on a single plain line', $response->headers->get('X-Debug-Error')); + } + protected function getRequestMock($isXmlHttpRequest = false, $requestFormat = 'html', $hasSession = true) { $request = $this->getMock( From 6ed9d0e4c17d75550f8c26d16967c42e2ebd308c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 28 Mar 2017 23:38:21 +0200 Subject: [PATCH 61/88] Fix @param in PHPDoc Errors reported by Sami API Doc generator on branch 3.2 ERROR: The "factory" @param tag variable name is wrong (should be "objectLoader") on "Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader::__construct" in src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php:68 ERROR: The "objectLoader" @param tag variable name is wrong (should be "factory") on "Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader::__construct" in src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php:68 ERROR: "7" @param tags are expected but only "6" found on "Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController::__construct" in src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php:50 ERROR: "3" @param tags are expected but only "2" found on "Symfony\Component\Asset\PathPackage::__construct" in src/Symfony/Component/Asset/PathPackage.php:35 ERROR: "2" @param tags are expected but only "1" found on "Symfony\Component\Cache\Adapter\PhpArrayAdapter::create" in src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php:64 ERROR: "3" @param tags are expected but only "1" found on "Symfony\Component\Cache\Adapter\RedisAdapter::__construct" in src/Symfony/Component/Cache/Adapter/RedisAdapter.php:39 ERROR: The "format" @param tag variable name is wrong (should be "fileLinkFormat") on "Symfony\Component\Debug\ExceptionHandler::setFileLinkFormat" in src/Symfony/Component/Debug/ExceptionHandler.php:90 ERROR: "2" @param tags are expected but only "3" found on "Symfony\Component\DependencyInjection\Compiler\Compiler::addPass" in src/Symfony/Component/DependencyInjection/Compiler/Compiler.php:73 ERROR: "2" @param tags are expected but only "3" found on "Symfony\Component\DependencyInjection\Compiler\PassConfig::addPass" in src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php:97 ERROR: "2" @param tags are expected but only "3" found on "Symfony\Component\DependencyInjection\ContainerBuilder::addCompilerPass" in src/Symfony/Component/DependencyInjection/ContainerBuilder.php:311 ERROR: "2" @param tags are expected but only "3" found on "Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface::getProxyFactoryCode" in src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.php:41 ERROR: "0" @param tags are expected but only "1" found on "Symfony\Component\HttpFoundation\Request::isMethodSafe" in src/Symfony/Component/HttpFoundation/Request.php:1458 ERROR: "5" @param tags are expected but only "6" found on "Symfony\Component\Serializer\Normalizer\AbstractNormalizer::instantiateObject" in src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php:291 --- .../Form/ChoiceList/DoctrineChoiceLoader.php | 2 +- .../Controller/ProfilerController.php | 13 +++++++------ src/Symfony/Component/Asset/PathPackage.php | 1 + .../Component/Cache/Adapter/PhpArrayAdapter.php | 3 ++- .../Component/Cache/Adapter/RedisAdapter.php | 4 +++- src/Symfony/Component/Debug/ExceptionHandler.php | 2 +- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php index 9477d8265529d..f199f16265fac 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php @@ -61,9 +61,9 @@ class DoctrineChoiceLoader implements ChoiceLoaderInterface * loaded objects * @param IdReader $idReader The reader for the object * IDs. + * @param null|EntityLoaderInterface $objectLoader The objects loader * @param ChoiceListFactoryInterface $factory The factory for creating * the loaded choice list - * @param null|EntityLoaderInterface $objectLoader The objects loader */ public function __construct($manager, $class, $idReader = null, $objectLoader = null, $factory = null) { diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php index d811421b0066b..33092d36466cd 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php @@ -40,12 +40,13 @@ class ProfilerController /** * Constructor. * - * @param UrlGeneratorInterface $generator The URL Generator - * @param Profiler $profiler The profiler - * @param \Twig_Environment $twig The twig environment - * @param array $templates The templates - * @param string $toolbarPosition The toolbar position (top, bottom, normal, or null -- use the configuration) - * @param string $baseDir The project root directory + * @param UrlGeneratorInterface $generator The URL Generator + * @param Profiler $profiler The profiler + * @param \Twig_Environment $twig The twig environment + * @param array $templates The templates + * @param string $toolbarPosition The toolbar position (top, bottom, normal, or null -- use the configuration) + * @param ContentSecurityPolicyHandler $cspHandler The Content-Security-Policy handler + * @param string $baseDir The project root directory */ public function __construct(UrlGeneratorInterface $generator, Profiler $profiler = null, \Twig_Environment $twig, array $templates, $toolbarPosition = 'bottom', ContentSecurityPolicyHandler $cspHandler = null, $baseDir = null) { diff --git a/src/Symfony/Component/Asset/PathPackage.php b/src/Symfony/Component/Asset/PathPackage.php index 906879f8b064d..a8785c53f4303 100644 --- a/src/Symfony/Component/Asset/PathPackage.php +++ b/src/Symfony/Component/Asset/PathPackage.php @@ -31,6 +31,7 @@ class PathPackage extends Package /** * @param string $basePath The base path to be prepended to relative paths * @param VersionStrategyInterface $versionStrategy The version strategy + * @param ContextInterface|null $context The context */ public function __construct($basePath, VersionStrategyInterface $versionStrategy, ContextInterface $context = null) { diff --git a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php index 4b1552e1d16c9..ad287576f59d3 100644 --- a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php @@ -57,7 +57,8 @@ function ($key, $value, $isHit) { * stores arrays in its latest versions. This factory method decorates the given * fallback pool with this adapter only if the current PHP version is supported. * - * @param string $file The PHP file were values are cached + * @param string $file The PHP file were values are cached + * @param CacheItemPoolInterface $fallbackPool Fallback for old PHP versions or opcache disabled * * @return CacheItemPoolInterface */ diff --git a/src/Symfony/Component/Cache/Adapter/RedisAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisAdapter.php index 51a35c6f71ab9..5cae772ef7fc8 100644 --- a/src/Symfony/Component/Cache/Adapter/RedisAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/RedisAdapter.php @@ -34,7 +34,9 @@ class RedisAdapter extends AbstractAdapter private $redis; /** - * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient The redis client + * @param string $namespace The default namespace + * @param integer $defaultLifetime The default lifetime */ public function __construct($redisClient, $namespace = '', $defaultLifetime = 0) { diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php index 2fdd8456fdf76..f2ae4b102e13d 100644 --- a/src/Symfony/Component/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/Debug/ExceptionHandler.php @@ -83,7 +83,7 @@ public function setHandler(callable $handler = null) /** * Sets the format for links to source files. * - * @param string|FileLinkFormatter $format The format for links to source files + * @param string|FileLinkFormatter $fileLinkFormat The format for links to source files * * @return string The previous file link format */ From 17f1f079b2cec445e1e10b4f9dc936534b8b029d Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Mon, 27 Mar 2017 22:18:06 +0200 Subject: [PATCH 62/88] [Console] Revised exception rendering --- src/Symfony/Component/Console/Application.php | 13 ++++++------- .../Component/Console/Tests/ApplicationTest.php | 16 ++++++++++++++++ .../application_renderexception_escapeslines.txt | 9 +++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_escapeslines.txt diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 32bd8373db221..bc5e9ee66c09b 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -650,12 +650,11 @@ public function renderException($e, $output) if (defined('HHVM_VERSION') && $width > 1 << 31) { $width = 1 << 31; } - $formatter = $output->getFormatter(); $lines = array(); - foreach (preg_split('/\r?\n/', OutputFormatter::escape($e->getMessage())) as $line) { + foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) { foreach ($this->splitStringByWidth($line, $width - 4) as $line) { // pre-format lines to get the right string length - $lineLength = $this->stringWidth(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4; + $lineLength = $this->stringWidth($line) + 4; $lines[] = array($line, $lineLength); $len = max($lineLength, $len); @@ -663,15 +662,15 @@ public function renderException($e, $output) } $messages = array(); - $messages[] = $emptyLine = $formatter->format(sprintf('%s', str_repeat(' ', $len))); - $messages[] = $formatter->format(sprintf('%s%s', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title))))); + $messages[] = $emptyLine = sprintf('%s', str_repeat(' ', $len)); + $messages[] = sprintf('%s%s', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title)))); foreach ($lines as $line) { - $messages[] = $formatter->format(sprintf(' %s %s', $line[0], str_repeat(' ', $len - $line[1]))); + $messages[] = sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); } $messages[] = $emptyLine; $messages[] = ''; - $output->writeln($messages, OutputInterface::OUTPUT_RAW); + $output->writeln($messages); if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $output->writeln('Exception trace:'); diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 895fdb926142f..df6d1976e7193 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -591,6 +591,22 @@ public function testRenderExceptionWithDoubleWidthCharacters() $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth2.txt', $tester->getDisplay(true), '->renderException() wraps messages when they are bigger than the terminal'); } + public function testRenderExceptionEscapesLines() + { + $application = $this->getMockBuilder('Symfony\Component\Console\Application')->setMethods(array('getTerminalWidth'))->getMock(); + $application->setAutoExit(false); + $application->expects($this->any()) + ->method('getTerminalWidth') + ->will($this->returnValue(22)); + $application->register('foo')->setCode(function () { + throw new \Exception('dont break here !'); + }); + $tester = new ApplicationTester($application); + + $tester->run(array('command' => 'foo'), array('decorated' => false)); + $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_escapeslines.txt', $tester->getDisplay(true), '->renderException() escapes lines containing formatting'); + } + public function testRun() { $application = new Application(); diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_escapeslines.txt b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_escapeslines.txt new file mode 100644 index 0000000000000..cf79b37a92d6e --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_renderexception_escapeslines.txt @@ -0,0 +1,9 @@ + + + [Exception] + dont break here < + info>! + + +foo + From 53ecf8393e976dd1585e9230e0cd4d1997d31760 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Wed, 29 Mar 2017 15:52:26 +0200 Subject: [PATCH 63/88] [Console] Fix table cell styling --- .../Component/Console/Helper/Helper.php | 7 ++++- .../Component/Console/Helper/Table.php | 11 ++++--- .../Console/Tests/Helper/TableTest.php | 29 +++++++++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Component/Console/Helper/Helper.php index 90979d5b9d5e3..b429e630c7217 100644 --- a/src/Symfony/Component/Console/Helper/Helper.php +++ b/src/Symfony/Component/Console/Helper/Helper.php @@ -109,6 +109,11 @@ public static function formatMemory($memory) } public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string) + { + return self::strlen(self::removeDecoration($formatter, $string)); + } + + public static function removeDecoration(OutputFormatterInterface $formatter, $string) { $isDecorated = $formatter->isDecorated(); $formatter->setDecorated(false); @@ -118,6 +123,6 @@ public static function strlenWithoutDecoration(OutputFormatterInterface $formatt $string = preg_replace("/\033\[[^m]*m/", '', $string); $formatter->setDecorated($isDecorated); - return self::strlen($string); + return $string; } } diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 8728e33d8396d..11bed884c2aca 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -341,7 +341,7 @@ private function buildTableRows($rows) if (!strstr($cell, "\n")) { continue; } - $lines = explode("\n", $cell); + $lines = explode("\n", str_replace("\n", "\n", $cell)); foreach ($lines as $lineKey => $line) { if ($cell instanceof TableCell) { $line = new TableCell($line, array('colspan' => $cell->getColspan())); @@ -382,7 +382,7 @@ private function fillNextRows($rows, $line) $nbLines = $cell->getRowspan() - 1; $lines = array($cell); if (strstr($cell, "\n")) { - $lines = explode("\n", $cell); + $lines = explode("\n", str_replace("\n", "\n", $cell)); $nbLines = count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines; $rows[$line][$column] = new TableCell($lines[0], array('colspan' => $cell->getColspan())); @@ -514,6 +514,8 @@ private function getColumnWidth($column) return $this->columnWidths[$column]; } + $lengths = array(); + foreach (array_merge($this->headers, $this->rows) as $row) { if ($row instanceof TableSeparator) { continue; @@ -521,9 +523,10 @@ private function getColumnWidth($column) foreach ($row as $i => $cell) { if ($cell instanceof TableCell) { - $textLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell); + $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); + $textLength = Helper::strlen($textContent); if ($textLength > 0) { - $contentColumns = str_split($cell, ceil($textLength / $cell->getColspan())); + $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan())); foreach ($contentColumns as $position => $content) { $row[$i + $position] = $content; } diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 5fe6b645602fa..0e984324e7095 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -511,6 +511,35 @@ public function renderProvider() | Dante Alighieri | J. R. R. Tolkien | J. R. R | +-----------------+------------------+---------+ +TABLE + , + true, + ), + 'Row with formatted cells containing a newline' => array( + array(), + array( + array( + new TableCell('Dont break'."\n".'here', array('colspan' => 2)), + ), + new TableSeparator(), + array( + 'foo', + new TableCell('Dont break'."\n".'here', array('rowspan' => 2)), + ), + array( + 'bar', + ), + ), + 'default', + <<<'TABLE' ++-------+------------+ +| Dont break | +| here | ++-------+------------+ +| foo | Dont break | +| bar | here | ++-------+------------+ + TABLE , true, From dc55db2a9db59dacfca599ec5efc3b5e985767ba Mon Sep 17 00:00:00 2001 From: Philipp Kretzschmar Date: Wed, 27 Jul 2016 18:41:51 +0200 Subject: [PATCH 64/88] add expression text to SyntaxError fixes #19445 --- .../Component/ExpressionLanguage/Lexer.php | 5 +-- .../ExpressionLanguage/SyntaxError.php | 10 ++++-- .../ExpressionLanguage/Tests/LexerTest.php | 33 +++++++++++++++++-- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/ExpressionLanguage/Lexer.php b/src/Symfony/Component/ExpressionLanguage/Lexer.php index 26bb51d42e35e..3d3aba25add1d 100644 --- a/src/Symfony/Component/ExpressionLanguage/Lexer.php +++ b/src/Symfony/Component/ExpressionLanguage/Lexer.php @@ -87,7 +87,8 @@ public function tokenize($expression) $cursor += strlen($match[0]); } else { // unlexable - throw new SyntaxError(sprintf('Unexpected character "%s"', $expression[$cursor]), $cursor); + $message = sprintf('Unexpected character "%s"', $expression[$cursor]); + throw new SyntaxError($message, $cursor, $expression); } } @@ -95,7 +96,7 @@ public function tokenize($expression) if (!empty($brackets)) { list($expect, $cur) = array_pop($brackets); - throw new SyntaxError(sprintf('Unclosed "%s"', $expect), $cur); + throw new SyntaxError(sprintf('Unclosed "%s"', $expect), $cur, $expression); } return new TokenStream($tokens); diff --git a/src/Symfony/Component/ExpressionLanguage/SyntaxError.php b/src/Symfony/Component/ExpressionLanguage/SyntaxError.php index d149c00768ad8..c30f6e62f778b 100644 --- a/src/Symfony/Component/ExpressionLanguage/SyntaxError.php +++ b/src/Symfony/Component/ExpressionLanguage/SyntaxError.php @@ -13,8 +13,14 @@ class SyntaxError extends \LogicException { - public function __construct($message, $cursor = 0) + public function __construct($message, $cursor = 0, $expression = '') { - parent::__construct(sprintf('%s around position %d.', $message, $cursor)); + $message = sprintf('%s around position %d', $message, $cursor); + if ($expression) { + $message = sprintf('%s for expression "%s"', $message, $expression); + } + $message .= '.'; + + parent::__construct($message); } } diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/LexerTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/LexerTest.php index 4292c22359692..a28537493d971 100644 --- a/src/Symfony/Component/ExpressionLanguage/Tests/LexerTest.php +++ b/src/Symfony/Component/ExpressionLanguage/Tests/LexerTest.php @@ -18,14 +18,43 @@ class LexerTest extends TestCase { + /** + * @var Lexer + */ + private $lexer; + + protected function setUp() + { + $this->lexer = new Lexer(); + } + /** * @dataProvider getTokenizeData */ public function testTokenize($tokens, $expression) { $tokens[] = new Token('end of expression', null, strlen($expression) + 1); - $lexer = new Lexer(); - $this->assertEquals(new TokenStream($tokens), $lexer->tokenize($expression)); + $this->assertEquals(new TokenStream($tokens), $this->lexer->tokenize($expression)); + } + + /** + * @expectedException Symfony\Component\ExpressionLanguage\SyntaxError + * @expectedExceptionMessage Unexpected character "'" around position 33 for expression "service(faulty.expression.example').dummyMethod()". + */ + public function testTokenizeThrowsErrorWithMessage() + { + $expression = "service(faulty.expression.example').dummyMethod()"; + $this->lexer->tokenize($expression); + } + + /** + * @expectedException Symfony\Component\ExpressionLanguage\SyntaxError + * @expectedExceptionMessage Unclosed "(" around position 7 for expression "service(unclosed.expression.dummyMethod()". + */ + public function testTokenizeThrowsErrorOnUnclosedBrace() + { + $expression = 'service(unclosed.expression.dummyMethod()'; + $this->lexer->tokenize($expression); } public function getTokenizeData() From fb4d8de5e4c99d074d6b8f67f9251671014a931b Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Fri, 31 Mar 2017 10:23:48 +0200 Subject: [PATCH 65/88] Avoid forcing to define the choices_as_values option when using choice_loader When using the choice loader, choices are ignored entirely. Forcing the dev to add the choices_as_values just to avoid the deprecation warning (and then to remove the option again at some point in 3.x due to deprecation) is a bad developer experience. --- src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index 26f7c80f17660..61907067f5762 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -357,7 +357,7 @@ public function configureOptions(OptionsResolver $resolver) }; $choicesAsValuesNormalizer = function (Options $options, $choicesAsValues) use ($that) { - if (true !== $choicesAsValues) { + if (true !== $choicesAsValues && null === $options['choice_loader']) { @trigger_error(sprintf('The value "false" for the "choices_as_values" option of the "%s" form type (%s) is deprecated since version 2.8 and will not be supported anymore in 3.0. Set this option to "true" and flip the contents of the "choices" option instead.', $that->getName(), __CLASS__), E_USER_DEPRECATED); } From 071548090bbd098347729ade45c020c5cc7bfcef Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Fri, 31 Mar 2017 14:24:41 +0200 Subject: [PATCH 66/88] Fix tests expecting a valid date --- .../Component/Form/Tests/Extension/Core/Type/DateTypeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php index d907c9c3d15e2..05fc63f055b5a 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php @@ -598,7 +598,7 @@ public function testIsSynchronizedReturnsTrueIfChoiceAndCompletelyFilled() )); $form->submit(array( - 'day' => '0', + 'day' => '1', 'month' => '6', 'year' => '2010', )); From 9a1915f88bf3ffc6b40a6342ff604c5eff368223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sat, 1 Apr 2017 00:21:40 +0200 Subject: [PATCH 67/88] [EventDispatcher] Remove unneded count() --- src/Symfony/Component/EventDispatcher/EventDispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 87aca2d480ec2..d54ecad6bd367 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -80,7 +80,7 @@ public function getListeners($eventName = null) */ public function hasListeners($eventName = null) { - return (bool) count($this->getListeners($eventName)); + return (bool) $this->getListeners($eventName); } /** From 75d5cb1bad123378a0b2202647dd172609a7a541 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 2 Apr 2017 15:23:09 +0200 Subject: [PATCH 68/88] Disable resource tracking if the config component is missing --- .../Component/DependencyInjection/ContainerBuilder.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 496adb9426fcb..5bafa94398e61 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -26,6 +26,7 @@ use Symfony\Component\Config\Resource\ResourceInterface; use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface; use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; @@ -73,7 +74,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface */ private $compiler; - private $trackResources = true; + private $trackResources; /** * @var InstantiatorInterface|null @@ -90,6 +91,13 @@ class ContainerBuilder extends Container implements TaggedContainerInterface */ private $expressionLanguageProviders = array(); + public function __construct(ParameterBagInterface $parameterBag = null) + { + parent::__construct($parameterBag); + + $this->trackResources = interface_exists('Symfony\Component\Config\Resource\ResourceInterface'); + } + /** * Sets the track resources flag. * From 0f623f422019fb450feb2fda0c1aac91b9c6d162 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Fri, 31 Mar 2017 11:34:31 +0200 Subject: [PATCH 69/88] CS: Remove invisible chars --- .../DataTransformer/PercentToLocalizedStringTransformer.php | 2 +- .../Component/Form/Extension/Validator/ValidatorExtension.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php index 88531feaa222c..7fc191a054ff4 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php @@ -120,7 +120,7 @@ public function reverseTransform($value) $formatter = $this->getNumberFormatter(); // replace normal spaces so that the formatter can read them - $value = $formatter->parse(str_replace(' ', ' ', $value)); + $value = $formatter->parse(str_replace(' ', "\xc2\xa0", $value)); if (intl_is_failure($formatter->getErrorCode())) { throw new TransformationFailedException($formatter->getErrorMessage()); diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php index e7ed95c459d03..5548493e8c9c4 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php @@ -59,7 +59,7 @@ public function __construct($validator) public function loadTypeGuesser() { - // 2.5 API + // 2.5 API if ($this->validator instanceof ValidatorInterface) { return new ValidatorTypeGuesser($this->validator); } From 7cd744133d74a976f69a33d0dbc1d5983dc30642 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Fri, 31 Mar 2017 10:01:13 +0200 Subject: [PATCH 70/88] Complete the injection of the expression in all syntax errors --- .../Component/ExpressionLanguage/Lexer.php | 9 ++++---- .../Component/ExpressionLanguage/Parser.php | 14 ++++++------- .../ExpressionLanguage/SyntaxError.php | 2 +- .../ExpressionLanguage/Tests/LexerTest.php | 10 ++++----- .../ExpressionLanguage/Tests/ParserTest.php | 4 ++-- .../ExpressionLanguage/TokenStream.php | 21 +++++++++++++++---- 6 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/Symfony/Component/ExpressionLanguage/Lexer.php b/src/Symfony/Component/ExpressionLanguage/Lexer.php index 3d3aba25add1d..8c10b72d86046 100644 --- a/src/Symfony/Component/ExpressionLanguage/Lexer.php +++ b/src/Symfony/Component/ExpressionLanguage/Lexer.php @@ -59,12 +59,12 @@ public function tokenize($expression) } elseif (false !== strpos(')]}', $expression[$cursor])) { // closing bracket if (empty($brackets)) { - throw new SyntaxError(sprintf('Unexpected "%s"', $expression[$cursor]), $cursor); + throw new SyntaxError(sprintf('Unexpected "%s"', $expression[$cursor]), $cursor, $expression); } list($expect, $cur) = array_pop($brackets); if ($expression[$cursor] != strtr($expect, '([{', ')]}')) { - throw new SyntaxError(sprintf('Unclosed "%s"', $expect), $cur); + throw new SyntaxError(sprintf('Unclosed "%s"', $expect), $cur, $expression); } $tokens[] = new Token(Token::PUNCTUATION_TYPE, $expression[$cursor], $cursor + 1); @@ -87,8 +87,7 @@ public function tokenize($expression) $cursor += strlen($match[0]); } else { // unlexable - $message = sprintf('Unexpected character "%s"', $expression[$cursor]); - throw new SyntaxError($message, $cursor, $expression); + throw new SyntaxError(sprintf('Unexpected character "%s"', $expression[$cursor]), $cursor, $expression); } } @@ -99,6 +98,6 @@ public function tokenize($expression) throw new SyntaxError(sprintf('Unclosed "%s"', $expect), $cur, $expression); } - return new TokenStream($tokens); + return new TokenStream($tokens, $expression); } } diff --git a/src/Symfony/Component/ExpressionLanguage/Parser.php b/src/Symfony/Component/ExpressionLanguage/Parser.php index f121ad9a9cdd8..6f90451522290 100644 --- a/src/Symfony/Component/ExpressionLanguage/Parser.php +++ b/src/Symfony/Component/ExpressionLanguage/Parser.php @@ -99,7 +99,7 @@ public function parse(TokenStream $stream, $names = array()) $node = $this->parseExpression(); if (!$stream->isEOF()) { - throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s"', $stream->current->type, $stream->current->value), $stream->current->cursor); + throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s"', $stream->current->type, $stream->current->value), $stream->current->cursor, $stream->getExpression()); } return $node; @@ -195,13 +195,13 @@ public function parsePrimaryExpression() default: if ('(' === $this->stream->current->value) { if (false === isset($this->functions[$token->value])) { - throw new SyntaxError(sprintf('The function "%s" does not exist', $token->value), $token->cursor); + throw new SyntaxError(sprintf('The function "%s" does not exist', $token->value), $token->cursor, $this->stream->getExpression()); } $node = new Node\FunctionNode($token->value, $this->parseArguments()); } else { if (!in_array($token->value, $this->names, true)) { - throw new SyntaxError(sprintf('Variable "%s" is not valid', $token->value), $token->cursor); + throw new SyntaxError(sprintf('Variable "%s" is not valid', $token->value), $token->cursor, $this->stream->getExpression()); } // is the name used in the compiled code different @@ -227,7 +227,7 @@ public function parsePrimaryExpression() } elseif ($token->test(Token::PUNCTUATION_TYPE, '{')) { $node = $this->parseHashExpression(); } else { - throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s"', $token->type, $token->value), $token->cursor); + throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s"', $token->type, $token->value), $token->cursor, $this->stream->getExpression()); } } @@ -289,7 +289,7 @@ public function parseHashExpression() } else { $current = $this->stream->current; - throw new SyntaxError(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', $current->type, $current->value), $current->cursor); + throw new SyntaxError(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', $current->type, $current->value), $current->cursor, $this->stream->getExpression()); } $this->stream->expect(Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); @@ -327,7 +327,7 @@ public function parsePostfixExpression($node) // As a result, if $token is NOT an operator OR $token->value is NOT a valid property or method name, an exception shall be thrown. ($token->type !== Token::OPERATOR_TYPE || !preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A', $token->value)) ) { - throw new SyntaxError('Expected name', $token->cursor); + throw new SyntaxError('Expected name', $token->cursor, $this->stream->getExpression()); } $arg = new Node\ConstantNode($token->value); @@ -345,7 +345,7 @@ public function parsePostfixExpression($node) $node = new Node\GetAttrNode($node, $arg, $arguments, $type); } elseif ('[' === $token->value) { if ($node instanceof Node\GetAttrNode && Node\GetAttrNode::METHOD_CALL === $node->attributes['type'] && PHP_VERSION_ID < 50400) { - throw new SyntaxError('Array calls on a method call is only supported on PHP 5.4+', $token->cursor); + throw new SyntaxError('Array calls on a method call is only supported on PHP 5.4+', $token->cursor, $this->stream->getExpression()); } $this->stream->next(); diff --git a/src/Symfony/Component/ExpressionLanguage/SyntaxError.php b/src/Symfony/Component/ExpressionLanguage/SyntaxError.php index c30f6e62f778b..9373e9980b8f5 100644 --- a/src/Symfony/Component/ExpressionLanguage/SyntaxError.php +++ b/src/Symfony/Component/ExpressionLanguage/SyntaxError.php @@ -17,7 +17,7 @@ public function __construct($message, $cursor = 0, $expression = '') { $message = sprintf('%s around position %d', $message, $cursor); if ($expression) { - $message = sprintf('%s for expression "%s"', $message, $expression); + $message = sprintf('%s for expression `%s`', $message, $expression); } $message .= '.'; diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/LexerTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/LexerTest.php index a28537493d971..87c16f707b92c 100644 --- a/src/Symfony/Component/ExpressionLanguage/Tests/LexerTest.php +++ b/src/Symfony/Component/ExpressionLanguage/Tests/LexerTest.php @@ -34,12 +34,12 @@ protected function setUp() public function testTokenize($tokens, $expression) { $tokens[] = new Token('end of expression', null, strlen($expression) + 1); - $this->assertEquals(new TokenStream($tokens), $this->lexer->tokenize($expression)); + $this->assertEquals(new TokenStream($tokens, $expression), $this->lexer->tokenize($expression)); } /** - * @expectedException Symfony\Component\ExpressionLanguage\SyntaxError - * @expectedExceptionMessage Unexpected character "'" around position 33 for expression "service(faulty.expression.example').dummyMethod()". + * @expectedException \Symfony\Component\ExpressionLanguage\SyntaxError + * @expectedExceptionMessage Unexpected character "'" around position 33 for expression `service(faulty.expression.example').dummyMethod()`. */ public function testTokenizeThrowsErrorWithMessage() { @@ -48,8 +48,8 @@ public function testTokenizeThrowsErrorWithMessage() } /** - * @expectedException Symfony\Component\ExpressionLanguage\SyntaxError - * @expectedExceptionMessage Unclosed "(" around position 7 for expression "service(unclosed.expression.dummyMethod()". + * @expectedException \Symfony\Component\ExpressionLanguage\SyntaxError + * @expectedExceptionMessage Unclosed "(" around position 7 for expression `service(unclosed.expression.dummyMethod()`. */ public function testTokenizeThrowsErrorOnUnclosedBrace() { diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/ParserTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/ParserTest.php index 8996d5bfa0232..b4cfff6d1e756 100644 --- a/src/Symfony/Component/ExpressionLanguage/Tests/ParserTest.php +++ b/src/Symfony/Component/ExpressionLanguage/Tests/ParserTest.php @@ -20,7 +20,7 @@ class ParserTest extends TestCase { /** * @expectedException \Symfony\Component\ExpressionLanguage\SyntaxError - * @expectedExceptionMessage Variable "foo" is not valid around position 1. + * @expectedExceptionMessage Variable "foo" is not valid around position 1 for expression `foo`. */ public function testParseWithInvalidName() { @@ -31,7 +31,7 @@ public function testParseWithInvalidName() /** * @expectedException \Symfony\Component\ExpressionLanguage\SyntaxError - * @expectedExceptionMessage Variable "foo" is not valid around position 1. + * @expectedExceptionMessage Variable "foo" is not valid around position 1 for expression `foo`. */ public function testParseWithZeroInNames() { diff --git a/src/Symfony/Component/ExpressionLanguage/TokenStream.php b/src/Symfony/Component/ExpressionLanguage/TokenStream.php index 6c4af745b2cfe..3c22fc1d46ed3 100644 --- a/src/Symfony/Component/ExpressionLanguage/TokenStream.php +++ b/src/Symfony/Component/ExpressionLanguage/TokenStream.php @@ -22,16 +22,19 @@ class TokenStream private $tokens; private $position = 0; + private $expression; /** * Constructor. * - * @param array $tokens An array of tokens + * @param array $tokens An array of tokens + * @param string $expression */ - public function __construct(array $tokens) + public function __construct(array $tokens, $expression = '') { $this->tokens = $tokens; $this->current = $tokens[0]; + $this->expression = $expression; } /** @@ -50,7 +53,7 @@ public function __toString() public function next() { if (!isset($this->tokens[$this->position])) { - throw new SyntaxError('Unexpected end of expression', $this->current->cursor); + throw new SyntaxError('Unexpected end of expression', $this->current->cursor, $this->expression); } ++$this->position; @@ -69,7 +72,7 @@ public function expect($type, $value = null, $message = null) { $token = $this->current; if (!$token->test($type, $value)) { - throw new SyntaxError(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)', $message ? $message.'. ' : '', $token->type, $token->value, $type, $value ? sprintf(' with value "%s"', $value) : ''), $token->cursor); + throw new SyntaxError(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)', $message ? $message.'. ' : '', $token->type, $token->value, $type, $value ? sprintf(' with value "%s"', $value) : ''), $token->cursor, $this->expression); } $this->next(); } @@ -83,4 +86,14 @@ public function isEOF() { return $this->current->type === Token::EOF_TYPE; } + + /** + * @internal + * + * @return string + */ + public function getExpression() + { + return $this->expression; + } } From 74ee588924cf2e88a5c64d48d6e6ea1283b77bdc Mon Sep 17 00:00:00 2001 From: Arthur de Moulins Date: Mon, 3 Apr 2017 11:21:18 +0200 Subject: [PATCH 71/88] support nullable array or collection --- .../Component/PropertyInfo/Extractor/PhpDocExtractor.php | 6 +++--- .../PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php | 1 + .../Tests/Extractors/ReflectionExtractorTest.php | 1 + .../Component/PropertyInfo/Tests/Fixtures/Dummy.php | 7 +++++++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index 73e8ad3748977..b6b39cc0fc5ec 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -242,7 +242,7 @@ private function getDocBlockFromProperty($class, $property) * @param string $ucFirstProperty * @param int $type * - * @return DocBlock|null + * @return array|null */ private function getDocBlockFromMethod($class, $ucFirstProperty, $type) { @@ -337,10 +337,10 @@ private function createType($docType, $nullable) $collectionValueType = null; } else { $collectionKeyType = new Type(Type::BUILTIN_TYPE_INT); - $collectionValueType = new Type($phpType, false, $class); + $collectionValueType = new Type($phpType, $nullable, $class); } - return new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, $collectionKeyType, $collectionValueType); + return new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, $collectionKeyType, $collectionValueType); } return new Type($phpType, $nullable, $class); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php index 10439974820b2..6477ba1967721 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php @@ -68,6 +68,7 @@ public function typesProvider() array('d', array(new Type(Type::BUILTIN_TYPE_BOOL)), null, null), array('e', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_RESOURCE))), null, null), array('f', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null), + array('g', array(new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)), 'Nullable array.', null), array('donotexist', null, null, null), array('staticGetter', null, null, null), array('staticSetter', null, null, null), diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php index 7818d0dd4004d..6af92affe03d5 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php @@ -38,6 +38,7 @@ public function testGetProperties() 'parent', 'collection', 'B', + 'g', 'foo', 'foo2', 'foo3', diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php index 96cb87db4a8fa..12065b18b62a3 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -51,6 +51,13 @@ class Dummy extends ParentDummy */ public $B; + /** + * Nullable array. + * + * @var array|null + */ + public $g; + public static function getStatic() { } From 8c8b181f063b30b9d4df17fe6b1e9c05516525eb Mon Sep 17 00:00:00 2001 From: Dany Maillard Date: Mon, 3 Apr 2017 10:42:32 +0200 Subject: [PATCH 72/88] Lighten tests output by removing composer suggestions --- .travis.yml | 6 +++--- appveyor.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 088de9fec465a..7205200d85e1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -79,7 +79,7 @@ install: - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev - if [[ ! $skip && $deps ]]; then export SYMFONY_DEPRECATIONS_HELPER=weak; fi - if [[ ! $skip && $deps ]]; then mv composer.json.phpunit composer.json; fi - - if [[ ! $skip ]]; then composer update; fi + - if [[ ! $skip ]]; then composer update --no-suggest; fi - if [[ ! $skip ]]; then ./phpunit install; fi - if [[ ! $skip && ! $PHP = hhvm* ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi @@ -90,5 +90,5 @@ script: - if [[ ! $deps && ! $PHP = hhvm* ]]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty; fi - if [[ ! $deps && $PHP = hhvm* ]]; then $PHPUNIT --exclude-group benchmark,intl-data; fi - if [[ ! $deps && $PHP = ${MIN_PHP%.*} ]]; then echo -e "1\\n0" | xargs -I{} sh -c 'echo "\\nPHP --enable-sigchild enhanced={}" && ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/'; fi - - if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --no-progress --ansi; $PHPUNIT --exclude-group tty,benchmark,intl-data'$LEGACY"$REPORT"; fi - - if [[ $deps = low ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --no-progress --ansi --prefer-lowest --prefer-stable; $PHPUNIT --exclude-group tty,benchmark,intl-data'"$REPORT"; fi + - if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --no-progress --no-suggest --ansi; $PHPUNIT --exclude-group tty,benchmark,intl-data'$LEGACY"$REPORT"; fi + - if [[ $deps = low ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --no-progress --no-suggest --ansi --prefer-lowest --prefer-stable; $PHPUNIT --exclude-group tty,benchmark,intl-data'"$REPORT"; fi diff --git a/appveyor.yml b/appveyor.yml index 5f3953ed8acca..86a943c77c42e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -53,7 +53,7 @@ install: - copy /Y .composer\* %APPDATA%\Composer\ - php .github/build-packages.php "HEAD^" src\Symfony\Bridge\PhpUnit - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) - - php composer.phar update --no-progress --ansi + - php composer.phar update --no-progress --no-suggest --ansi - php phpunit install test_script: From 992c6775340b53ab0e2f756ac512929581135305 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 3 Apr 2017 17:01:14 +0200 Subject: [PATCH 73/88] [DI] Don't use auto-registered services to populate type-candidates --- .../Compiler/AutowirePass.php | 56 +++++++++++-------- .../Tests/Compiler/AutowirePassTest.php | 21 ------- 2 files changed, 32 insertions(+), 45 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 9454d1bd4b1ad..445a544f41492 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -28,7 +28,7 @@ class AutowirePass implements CompilerPassInterface private $definedTypes = array(); private $types; private $notGuessableTypes = array(); - private $usedTypes = array(); + private $autowired = array(); /** * {@inheritdoc} @@ -45,15 +45,6 @@ public function process(ContainerBuilder $container) $this->completeDefinition($id, $definition); } } - - foreach ($this->usedTypes as $type => $id) { - if (isset($this->usedTypes[$type]) && isset($this->notGuessableTypes[$type])) { - $classOrInterface = class_exists($type) ? 'class' : 'interface'; - $matchingServices = implode(', ', $this->types[$type]); - - throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $type, $id, $classOrInterface, $matchingServices)); - } - } } catch (\Exception $e) { } catch (\Throwable $e) { } @@ -66,7 +57,7 @@ public function process(ContainerBuilder $container) $this->definedTypes = array(); $this->types = null; $this->notGuessableTypes = array(); - $this->usedTypes = array(); + $this->autowired = array(); if (isset($e)) { throw $e; @@ -92,47 +83,56 @@ private function completeDefinition($id, Definition $definition) if (!$constructor = $reflectionClass->getConstructor()) { return; } + $parameters = $constructor->getParameters(); + if (method_exists('ReflectionMethod', 'isVariadic') && $constructor->isVariadic()) { + array_pop($parameters); + } $arguments = $definition->getArguments(); - foreach ($constructor->getParameters() as $index => $parameter) { + foreach ($parameters as $index => $parameter) { if (array_key_exists($index, $arguments) && '' !== $arguments[$index]) { continue; } try { if (!$typeHint = $parameter->getClass()) { + if (isset($arguments[$index])) { + continue; + } + // no default value? Then fail if (!$parameter->isOptional()) { throw new RuntimeException(sprintf('Unable to autowire argument index %d ($%s) for the service "%s". If this is an object, give it a type-hint. Otherwise, specify this argument\'s value explicitly.', $index, $parameter->name, $id)); } - if (!array_key_exists($index, $arguments)) { - // specifically pass the default value - $arguments[$index] = $parameter->getDefaultValue(); - } + // specifically pass the default value + $arguments[$index] = $parameter->getDefaultValue(); continue; } + if (isset($this->autowired[$typeHint->name])) { + return $this->autowired[$typeHint->name] ? new Reference($this->autowired[$typeHint->name]) : null; + } + if (null === $this->types) { $this->populateAvailableTypes(); } if (isset($this->types[$typeHint->name]) && !isset($this->notGuessableTypes[$typeHint->name])) { $value = new Reference($this->types[$typeHint->name]); - $this->usedTypes[$typeHint->name] = $id; } else { try { $value = $this->createAutowiredDefinition($typeHint, $id); - $this->usedTypes[$typeHint->name] = $id; } catch (RuntimeException $e) { - if ($parameter->allowsNull()) { - $value = null; - } elseif ($parameter->isDefaultValueAvailable()) { + if ($parameter->isDefaultValueAvailable()) { $value = $parameter->getDefaultValue(); + } elseif ($parameter->allowsNull()) { + $value = null; } else { throw $e; } + $this->autowired[$typeHint->name] = false; } } } catch (\ReflectionException $e) { @@ -148,6 +148,16 @@ private function completeDefinition($id, Definition $definition) $arguments[$index] = $value; } + if ($parameters && !isset($arguments[++$index])) { + while (0 <= --$index) { + $parameter = $parameters[$index]; + if (!$parameter->isDefaultValueAvailable() || $parameter->getDefaultValue() !== $arguments[$index]) { + break; + } + unset($arguments[$index]); + } + } + // it's possible index 1 was set, then index 0, then 2, etc // make sure that we re-order so they're injected as expected ksort($arguments); @@ -252,13 +262,11 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint, $id) throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface)); } - $argumentId = sprintf('autowired.%s', $typeHint->name); + $this->autowired[$typeHint->name] = $argumentId = sprintf('autowired.%s', $typeHint->name); $argumentDefinition = $this->container->register($argumentId, $typeHint->name); $argumentDefinition->setPublic(false); - $this->populateAvailableType($argumentId, $argumentDefinition); - try { $this->completeDefinition($argumentId, $argumentDefinition); } catch (RuntimeException $e) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 047801ceba8ea..9a41fa2ee0da5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -422,10 +422,6 @@ public function testOptionalScalarArgsNotPassedIfLast() array( new Reference('a'), new Reference('lille'), - // third arg shouldn't *need* to be passed - // but that's hard to "pull of" with autowiring, so - // this assumes passing the default val is ok - 'some_val', ), $definition->getArguments() ); @@ -462,23 +458,6 @@ public function testEmptyStringIsKept() $this->assertEquals(array(new Reference('a'), '', new Reference('lille')), $container->getDefinition('foo')->getArguments()); } - /** - * @dataProvider provideAutodiscoveredAutowiringOrder - * - * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMEssage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionA, autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionB). - */ - public function testAutodiscoveredAutowiringOrder($class) - { - $container = new ContainerBuilder(); - - $container->register('a', __NAMESPACE__.'\\'.$class) - ->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - public function provideAutodiscoveredAutowiringOrder() { return array( From 9b601633a724bf50d8479bf70e46bd33dc19ae5c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 3 Apr 2017 20:00:43 +0200 Subject: [PATCH 74/88] [DI] Autowiring and factories are incompatible with each others --- .../Compiler/AutowirePass.php | 4 ++++ .../Tests/Compiler/AutowirePassTest.php | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 9454d1bd4b1ad..8acf2856d5e1b 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -83,6 +83,10 @@ public function process(ContainerBuilder $container) */ private function completeDefinition($id, Definition $definition) { + if ($definition->getFactory() || $definition->getFactoryClass(false) || $definition->getFactoryService(false)) { + throw new RuntimeException(sprintf('Service "%s" can use either autowiring or a factory, not both.', $id)); + } + if (!$reflectionClass = $this->getReflectionClass($id, $definition)) { return; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 047801ceba8ea..6c17fcd66bb05 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -486,6 +486,22 @@ public function provideAutodiscoveredAutowiringOrder() array('CannotBeAutowiredReverseOrder'), ); } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Service "a" can use either autowiring or a factory, not both. + */ + public function testWithFactory() + { + $container = new ContainerBuilder(); + + $container->register('a', __NAMESPACE__.'\A') + ->setFactory('foo') + ->setAutowired(true); + + $pass = new AutowirePass(); + $pass->process($container); + } } class Foo From 8cf344b2af6b1dc8885fb63b045e9771dec75f6e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 3 Apr 2017 21:27:56 -0700 Subject: [PATCH 75/88] updated CHANGELOG for 2.7.26 --- CHANGELOG-2.7.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md index 5e137e4366aa7..bc4c0fa89d5fc 100644 --- a/CHANGELOG-2.7.md +++ b/CHANGELOG-2.7.md @@ -7,6 +7,37 @@ in 2.7 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.7.0...v2.7.1 +* 2.7.26 (2017-04-04) + + * bug #22229 [ExpressionLanguage] Provide the expression in syntax errors (k0pernikus, stof) + * bug #22240 [DI] Fix fatal error at ContainerBuilder::compile() if config is not installed (chalasr) + * bug #22140 [Form] Improve the exceptions when trying to get the data in a PRE_SET_DATA listener and the data has not already been set (fancyweb) + * bug #22217 [Console] Fix table cell styling (ro0NL) + * bug #22194 [Console] CommandTester: disable color support detection (julienfalque) + * bug #22188 [Console] Revised exception rendering (ro0NL) + * bug #22154 [WebProfilerBundle] Normalize whitespace in exceptions passed in headers (curry684) + * bug #22142 [Console] Escape exception messages in renderException (chalasr) + * bug #22172 Fix port usage in server:status command (alcaeus) + * bug #22164 [Bridge\Doctrine] Fix change breaking doctrine-bundle test suite (nicolas-grekas) + * bug #22133 [Filesystem] normalize paths before making them relative (xabbuh) + * bug #22138 [HttpFoundation][bugfix] $bags should always be initialized (MacDada) + * bug #21810 #21809 [SecurityBundle] bugfix: if security provider's name contains upper cases then container didn't compile (Antanas Arvasevicius) + * bug #19778 [Security] Fixed roles serialization on token from user object (eko) + * bug #22022 [Validator] fix URL validator to detect non supported chars according to RFC 3986 (e-moe) + * bug #21968 Fixed pathinfo calculation for requests starting with a question mark. (syzygymsu) + * bug #21846 [HttpFoundation] Fix Request::getHost() when having several hosts in X_FORWARDED_HOST (nicolas-grekas) + * bug #21208 [Validator] Add object handling of invalid constraints in Composite (SenseException) + * bug #22044 [Serializer] [XML] Ignore Process Instruction (jordscream) + * bug #22079 [HttpKernel] Fixed bug with purging of HTTPS URLs (ausi) + * bug #21523 #20411 fix Yaml parsing for very long quoted strings (RichardBradley) + * bug #22001 [Doctrine Bridge] fix priority for doctrine event listeners (dmaicher) + * bug #21981 [Console] Use proper line endings in BufferedOutput (julienfalque) + * bug #21957 [Form] Choice type int values (BC Fix) (mcfedr) + * bug #21923 [travis] Test with hhvm 3.18 (nicolas-grekas) + * bug #21823 dumpFile(), preserve existing file permissions (chs2) + * bug #21865 [Security] context listener: hardening user provider handling (xabbuh) + * bug #21883 [HttpKernel] fix Kernel name when stored in a directory starting with a number (fabpot) + * 2.7.25 (2017-03-06) * bug #21671 [Serializer] Xml encoder throws exception for valid data (gr1ev0us) From c06f35e4ebacd52224f85b60566186e268d03c7f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 3 Apr 2017 21:31:39 -0700 Subject: [PATCH 76/88] update CONTRIBUTORS for 2.7.26 --- CONTRIBUTORS.md | 72 ++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 73387b9f7bb1a..90b929e5efccb 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -23,25 +23,26 @@ Symfony is the result of the work of many people who made the code better - Pascal Borreli (pborreli) - Wouter De Jong (wouterj) - Romain Neutron (romain) + - Grégoire Pineau (lyrixx) - Joseph Bielawski (stloyd) - Karma Dordrak (drak) - Lukas Kahwe Smith (lsmith) - - Grégoire Pineau (lyrixx) - Martin Hasoň (hason) - - Jeremy Mikola (jmikola) + - Robin Chalas (chalas_r) - Maxime Steinhausser (ogizanagi) + - Jeremy Mikola (jmikola) - Jean-François Simon (jfsimon) - Benjamin Eberlei (beberlei) - Igor Wiedler (igorw) - - Robin Chalas (chalas_r) - Eriksen Costa (eriksencosta) - Jules Pietri (heah) - Sarah Khalil (saro0h) - Jonathan Wage (jwage) + - Guilhem Niot (energetick) - Diego Saint Esteben (dosten) + - Roland Franssen (ro0) - Alexandre Salomé (alexandresalome) - William Durand (couac) - - Guilhem Niot (energetick) - ornicar - Francis Besset (francisbesset) - stealth35 ‏ (stealth35) @@ -50,20 +51,20 @@ Symfony is the result of the work of many people who made the code better - Peter Rehm (rpet) - Saša Stamenković (umpirsky) - Henrik Bjørnskov (henrikbjorn) - - Roland Franssen (ro0) - Miha Vrhovnik - Iltar van der Berg (kjarli) - Diego Saint Esteben (dii3g0) - Konstantin Kudryashov (everzet) - Bilal Amarni (bamarni) - Florin Patan (florinpatan) + - Matthias Pigulla (mpdude) - Kevin Bond (kbond) - Andrej Hudec (pulzarraider) - Gábor Egyed (1ed) - Michel Weimerskirch (mweimerskirch) - Eric Clemmons (ericclemmons) - Charles Sarrazin (csarrazi) - - Matthias Pigulla (mpdude) + - Pierre du Plessis (pierredup) - Christian Raue - Arnout Boks (aboks) - Deni @@ -71,39 +72,38 @@ Symfony is the result of the work of many people who made the code better - Dariusz Górecki (canni) - Titouan Galopin (tgalopin) - Douglas Greenshields (shieldo) - - Pierre du Plessis (pierredup) - Konstantin Myakshin (koc) - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) + - Jáchym Toušek (enumag) - Graham Campbell (graham) - Daniel Holmes (dholmes) - Toni Uebernickel (havvg) - Bart van den Burg (burgov) - Jordan Alliot (jalliot) + - Jérémy DERUSSÉ (jderusse) - John Wards (johnwards) - Fran Moreno (franmomu) - - Jáchym Toušek (enumag) - Antoine Hérault (herzult) - Paráda József (paradajozsef) - Dariusz Ruminski - Arnaud Le Blanc (arnaud-lb) - Jérôme Tamarelle (gromnan) + - Maxime STEINHAUSSER - Michal Piotrowski (eventhorizon) - Tim Nagel (merk) - - Maxime STEINHAUSSER - Issei Murasawa (issei_m) - Brice BERNARD (brikou) - Alexander M. Turek (derrabus) + - Baptiste Clavié (talus) - marc.weistroff - lenar - Włodzimierz Gajda (gajdaw) - - Baptiste Clavié (talus) - Vladimir Reznichenko (kalessil) - Alexander Schwenn (xelaris) - Florian Voutzinos (florianv) - Colin Frei - - Jérémy DERUSSÉ (jderusse) - Adrien Brault (adrienbrault) - Joshua Thijssen - Peter Kokot (maastermedia) @@ -148,6 +148,7 @@ Symfony is the result of the work of many people who made the code better - Teoh Han Hui (teohhanhui) - Clemens Tolboom - Helmer Aaviksoo + - Grégoire Paris (greg0ire) - Hiromi Hishida (77web) - Richard van Laak (rvanlaak) - Matthieu Ouellette-Vachon (maoueh) @@ -160,7 +161,7 @@ Symfony is the result of the work of many people who made the code better - Warnar Boekkooi (boekkooi) - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) - - Grégoire Paris (greg0ire) + - Dawid Nowak - Possum - Dorian Villet (gnutix) - Richard Miller (mr_r_miller) @@ -168,6 +169,7 @@ Symfony is the result of the work of many people who made the code better - Dennis Benkert (denderello) - Benjamin Dulau (dbenjamin) - Mathieu Lemoine (lemoinem) + - Chris Wilkinson (thewilkybarkid) - Andreas Hucks (meandmymonkey) - Noel Guilbert (noel) - Lars Strojny (lstrojny) @@ -191,16 +193,15 @@ Symfony is the result of the work of many people who made the code better - John Kary (johnkary) - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) - - Chris Wilkinson (thewilkybarkid) - Christian Schmidt - Michele Orselli (orso) - Tom Van Looy (tvlooy) - Sven Paulus (subsven) - Rui Marinho (ruimarinho) - SpacePossum - - Dawid Nowak - Eugene Wissner - Julien Brochet (mewt) + - Julien Falque (julienfalque) - Tristan Darricau (nicofuma) - Sergey Linnik (linniksa) - Michaël Perrin (michael.perrin) @@ -211,6 +212,7 @@ Symfony is the result of the work of many people who made the code better - julien pauli (jpauli) - Lorenz Schori - Sébastien Lavoie (lavoiesl) + - David Maicher (dmaicher) - Francois Zaninotto - Alexander Kotynia (olden) - Daniel Tschinder @@ -236,7 +238,6 @@ Symfony is the result of the work of many people who made the code better - Uwe Jäger (uwej711) - Eugene Leonovich (rybakit) - Filippo Tessarotto - - Julien Falque (julienfalque) - Joseph Rouff (rouffj) - Félix Labrecque (woodspire) - GordonsLondon @@ -258,7 +259,6 @@ Symfony is the result of the work of many people who made the code better - Beau Simensen (simensen) - Michael Hirschler (mvhirsch) - Robert Kiss (kepten) - - David Maicher (dmaicher) - Roumen Damianoff (roumen) - Antonio J. García Lagar (ajgarlag) - Kim Hemsø Rasmussen (kimhemsoe) @@ -396,6 +396,7 @@ Symfony is the result of the work of many people who made the code better - EdgarPE - Florian Pfitzer (marmelatze) - Asier Illarramendi (doup) + - Andreas Braun - Chris Sedlmayr (catchamonkey) - Seb Koelen - Dany Maillard (maidmaid) @@ -415,6 +416,7 @@ Symfony is the result of the work of many people who made the code better - Gintautas Miselis - Rob Bast - David Badura (davidbadura) + - Jordan Samouh (jordansamouh) - Zander Baldwin - Adam Harvey - Alex Bakhturin @@ -459,11 +461,13 @@ Symfony is the result of the work of many people who made the code better - Jakub Škvára (jskvara) - Andrew Udvare (audvare) - alexpods + - Nikolay Labinskiy (e-moe) - Arjen van der Meijden - Michele Locati - Dariusz Ruminski - Erik Trapman (eriktrapman) - De Cock Xavier (xdecock) + - Arthur de Moulins (4rthem) - Almog Baku (almogbaku) - Scott Arciszewski - Norbert Orzechowicz (norzechowicz) @@ -510,8 +514,10 @@ Symfony is the result of the work of many people who made the code better - Disquedur - Michiel Boeckaert (milio) - Geoffrey Tran (geoff) + - Romain Pierre (romain-pierre) - Jan Behrens - Mantas Var (mvar) + - Frank de Jonge (frenkynet) - Sebastian Krebs - Jean-Christophe Cuvelier [Artack] - Christopher Davis (chrisguitarguy) @@ -539,8 +545,8 @@ Symfony is the result of the work of many people who made the code better - Maxime Douailin - Jean Pasdeloup (pasdeloup) - Benjamin Cremer (bcremer) + - Thierry Thuon (lepiaf) - Javier López (loalf) - - Andreas Braun - Reinier Kip - Geoffrey Brier (geoffrey-brier) - Dustin Dobervich (dustin10) @@ -553,6 +559,7 @@ Symfony is the result of the work of many people who made the code better - Kamil Kokot (pamil) - Aurimas Niekis (gcds) - Max Grigorian (maxakawizard) + - mcfedr (mcfedr) - Rostyslav Kinash - Maciej Malarz (malarzm) - Daisuke Ohata @@ -570,6 +577,7 @@ Symfony is the result of the work of many people who made the code better - Denis Brumann (dbrumann) - Quentin de Longraye (quentinus95) - Chris Heng (gigablah) + - Richard Bradley - Ulumuddin Yunus (joenoez) - Luc Vieillescazes (iamluc) - Johann Saunier (prophet777) @@ -629,6 +637,7 @@ Symfony is the result of the work of many people who made the code better - Besnik Br - Dariusz Ruminski - Joshua Nye + - Claudio Zizza - Dave Marshall (davedevelopment) - avorobiev - Venu @@ -647,6 +656,7 @@ Symfony is the result of the work of many people who made the code better - John Bohn (jbohn) - Marc Morera (mmoreram) - Andrew Hilobok (hilobok) + - Noah Heck (myesain) - Christian Soronellas (theunic) - Yosmany Garcia (yosmanyga) - Wouter de Wild @@ -654,17 +664,18 @@ Symfony is the result of the work of many people who made the code better - Degory Valentine - Benoit Lévêque (benoit_leveque) - Jeroen Fiege (fieg) - - Arthur de Moulins (4rthem) - Krzysiek Łabuś - Xavier Lacot (xavier) - possum - Denis Zunke (donalberto) + - Ahmed TAILOULOUTE (ahmedtai) - Olivier Maisonneuve (olineuve) - Masterklavi - Francis Turmel (fturmel) - Nikita Nefedov (nikita2206) - cgonzalez - Ben + - Vincent Composieux (eko) - Jayson Xu (superjavason) - Jaik Dean (jaikdean) - fago @@ -675,6 +686,7 @@ Symfony is the result of the work of many people who made the code better - James Michael DuPont - Tom Klingenberg - Christopher Hall (mythmakr) + - Patrick Dawkins (pjcdawkins) - Paul Kamer (pkamer) - Rafał Wrzeszcz (rafalwrzeszcz) - Reen Lokum @@ -720,6 +732,7 @@ Symfony is the result of the work of many people who made the code better - corphi - grizlik - Derek ROTH + - Dmytro Boiko (eagle) - Shin Ohno (ganchiku) - Geert De Deckere (geertdd) - Jan Kramer (jankramer) @@ -782,7 +795,6 @@ Symfony is the result of the work of many people who made the code better - Phan Thanh Ha (haphan) - Chris Jones (leek) - Colin O'Dell (colinodell) - - Frank de Jonge (frenkynet) - xaav - Mahmoud Mostafa (mahmoud) - Alessandro Lai @@ -808,7 +820,6 @@ Symfony is the result of the work of many people who made the code better - Zachary Tong (polyfractal) - Hryhorii Hrebiniuk - Dennis Fridrich (dfridrich) - - mcfedr (mcfedr) - hamza - dantleech - Bastien DURAND (deamon) @@ -841,6 +852,7 @@ Symfony is the result of the work of many people who made the code better - Troy McCabe - Ville Mattila - ilyes kooli + - gr1ev0us - Boris Vujicic (boris.vujicic) - Max Beutel - Antanas Arvasevicius @@ -864,10 +876,12 @@ Symfony is the result of the work of many people who made the code better - Martynas Narbutas - Bailey Parker - Eddie Jaoude + - Antanas Arvasevicius - Haritz Iturbe (hizai) - Nerijus Arlauskas (nercury) - SPolischook - Diego Sapriza + - Anton A. Sumin - Joan Cruz - inspiran - Cristobal Dabed @@ -964,6 +978,7 @@ Symfony is the result of the work of many people who made the code better - Aharon Perkel - matze - Abdul.Mohsen B. A. A + - Martin Auswöger - Benoît Burnichon - pthompson - Malaney J. Hill @@ -1009,7 +1024,9 @@ Symfony is the result of the work of many people who made the code better - Klaas Cuvelier (kcuvelier) - markusu49 - Steve Frécinaux + - Jules Lamur - ShiraNai7 + - Markus Fasselt (digilist) - Vašek Purchart (vasek-purchart) - Janusz Jabłoński (yanoosh) - Sandro Hopf @@ -1034,17 +1051,16 @@ Symfony is the result of the work of many people who made the code better - Luis Galeas - Martin Pärtel - George Mponos (gmponos) - - Noah Heck (myesain) - Patrick Daley (padrig) - Xavier Briand (xavierbriand) - Max Summe - WedgeSama - Felds Liscia - - Ahmed TAILOULOUTE (ahmedtai) - Maxime Veber (nek-) - Sullivan SENECHAL - Tadcka - Beth Binkovitz + - Gonzalo Míguez - Romain Geissler - Adrien Moiruad - Tomaz Ahlin @@ -1104,7 +1120,6 @@ Symfony is the result of the work of many people who made the code better - Konrad Mohrfeldt - Lance Chen - Andrew (drew) - - Nikolay Labinskiy (e-moe) - kor3k kor3k (kor3k) - Stelian Mocanita (stelian) - Flavian (2much) @@ -1143,11 +1158,9 @@ Symfony is the result of the work of many people who made the code better - victoria - Francisco Facioni (fran6co) - Iwan van Staveren (istaveren) - - Thierry Thuon (lepiaf) - Povilas S. (povilas) - pborreli - Eric Caron - - Richard Bradley - 2manypeople - Wing - Thomas Bibb @@ -1171,6 +1184,7 @@ Symfony is the result of the work of many people who made the code better - Michal Gebauer - Gleb Sidora - David Stone + - Niels Keurentjes (curry684) - Jovan Perovic (jperovic) - Pablo Maria Martelletti (pmartelletti) - Yassine Guedidi (yguedidi) @@ -1228,6 +1242,7 @@ Symfony is the result of the work of many people who made the code better - Brian Graham (incognito) - Kevin Vergauwen (innocenzo) - Alessio Baglio (ioalessio) + - Johannes Müller (johmue) - Jordi Llonch (jordillonch) - Cédric Dugat (ph3nol) - Philip Dahlstrøm (phidah) @@ -1289,6 +1304,7 @@ Symfony is the result of the work of many people who made the code better - Jérémy M (th3mouk) - Vincent LEFORT (vlefort) - Sadicov Vladimir (xtech) + - Kevin EMO (zarcox) - Alexander Zogheb - Rémi Blaise - Joel Marcey @@ -1301,7 +1317,6 @@ Symfony is the result of the work of many people who made the code better - adenkejawen - Ari Pringle (apringle) - Dan Ordille (dordille) - - Dmytro Boiko (eagle) - Jan Eichhorn (exeu) - Grégory Pelletier (ip512) - John Nickell (jrnickell) @@ -1350,7 +1365,6 @@ Symfony is the result of the work of many people who made the code better - ddebree - Tomas Liubinas - Alex - - Patrick Dawkins - Klaas Naaijkens - Daniel González Cerviño - Rafał @@ -1363,7 +1377,6 @@ Symfony is the result of the work of many people who made the code better - David Joos (djoos) - Denis Klementjev (dklementjev) - Tomáš Polívka (draczris) - - Vincent Composieux (eko) - Franz Liedke (franzliedke) - Christophe BECKER (goabonga) - gondo (gondo) @@ -1399,6 +1412,7 @@ Symfony is the result of the work of many people who made the code better - Curtis - Gabriel Moreira - Alexey Popkov + - ChS - Joseph Deray - Damian Sromek - Ben @@ -1437,6 +1451,7 @@ Symfony is the result of the work of many people who made the code better - znerol - Christian Eikermann - Antonio Angelino + - Matt Fields - Shawn Iwinski - Niklas Keller - Vladimir Sazhin @@ -1562,6 +1577,7 @@ Symfony is the result of the work of many people who made the code better - ibasaw (ibasaw) - Vladislav Krupenkin (ideea) - Imangazaliev Muhammad (imangazaliev) + - j0k (j0k) - joris de wit (jdewit) - Jérémy CROMBEZ (jeremy) - Jose Manuel Gonzalez (jgonzalez) From 4cc567782e78eca265752650e33683d31dc21ed7 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 3 Apr 2017 21:31:58 -0700 Subject: [PATCH 77/88] updated VERSION for 2.7.26 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index be48c7359ba98..7e911bddfaaae 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.26-DEV'; + const VERSION = '2.7.26'; const VERSION_ID = 20726; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; const RELEASE_VERSION = 26; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From e580c68899921119e17b6774ef467406eb3b5f8b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 3 Apr 2017 21:47:45 -0700 Subject: [PATCH 78/88] bumped Symfony version to 2.7.27 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7e911bddfaaae..0d37a6d05e409 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.26'; - const VERSION_ID = 20726; + const VERSION = '2.7.27-DEV'; + const VERSION_ID = 20727; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; - const RELEASE_VERSION = 26; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 27; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From 4e661e7a73990e1b34f9594005f6614287f6ff21 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 4 Apr 2017 11:53:57 +0200 Subject: [PATCH 79/88] [Workflow] fix risky tests --- .../Workflow/Tests/Validator/StateMachineValidatorTest.php | 3 +++ .../Workflow/Tests/Validator/WorkflowValidatorTest.php | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php index 149d7d58f8e30..dccbf383049ad 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php @@ -94,6 +94,9 @@ public function testValid() (new StateMachineValidator())->validate($definition, 'foo'); + // the test simply ensures that the validation does not fail (i.e. it does not throw any exceptions) + $this->addToAssertionCount(1); + // The graph looks like: // // +----+ +----+ +---+ diff --git a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php index 60b2c7150e489..245617b682f54 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php @@ -28,6 +28,9 @@ public function testSinglePlaceWorkflowValidatorAndSimpleWorkflow() $definition = $this->createSimpleWorkflowDefinition(); (new WorkflowValidator(true))->validate($definition, 'foo'); + + // the test simply ensures that the validation does not fail (i.e. it does not throw any exceptions) + $this->addToAssertionCount(1); } /** @@ -60,5 +63,8 @@ public function testSameTransitionNameButNotSamePlace() $definition = new Definition($places, $transitions); (new WorkflowValidator())->validate($definition, 'foo'); + + // the test simply ensures that the validation does not fail (i.e. it does not throw any exceptions) + $this->addToAssertionCount(1); } } From 6b7172239250ace33b957d1616c199bd8f72a22a Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Tue, 4 Apr 2017 11:33:43 +0200 Subject: [PATCH 80/88] [Console] Fix render exception test --- src/Symfony/Component/Console/Tests/ApplicationTest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index e12922da35172..072f0d0b884b8 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -588,11 +588,9 @@ public function testRenderExceptionWithDoubleWidthCharacters() public function testRenderExceptionEscapesLines() { - $application = $this->getMockBuilder('Symfony\Component\Console\Application')->setMethods(array('getTerminalWidth'))->getMock(); + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(22)); + putenv('COLUMNS=22'); $application->register('foo')->setCode(function () { throw new \Exception('dont break here !'); }); @@ -600,6 +598,7 @@ public function testRenderExceptionEscapesLines() $tester->run(array('command' => 'foo'), array('decorated' => false)); $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_escapeslines.txt', $tester->getDisplay(true), '->renderException() escapes lines containing formatting'); + putenv('COLUMNS=120'); } public function testRun() From fffcd247b22f830330c277e4876aaf8772615e38 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 18 Mar 2017 10:10:35 +0100 Subject: [PATCH 81/88] fix some risky tests --- .../Builder/ArrayNodeDefinitionTest.php | 9 +- .../Definition/Builder/TreeBuilderTest.php | 13 ++- .../Config/Tests/Fixtures/BarNode.php | 18 ++++ .../Fixtures/Builder/BarNodeDefinition.php | 2 + .../Component/Form/Tests/CompoundFormTest.php | 2 + .../Extension/Core/Type/ChoiceTypeTest.php | 8 +- .../Extension/Core/Type/CountryTypeTest.php | 8 +- .../Extension/Core/Type/DateTimeTypeTest.php | 2 +- .../Extension/Core/Type/DateTypeTest.php | 2 +- .../Extension/Core/Type/FormTypeTest.php | 14 +-- .../Extension/Core/Type/TimeTypeTest.php | 2 +- .../DependencyInjectionExtensionTest.php | 9 +- .../Component/Form/Tests/FormBuilderTest.php | 2 + .../Component/Form/Tests/FormConfigTest.php | 102 +++++++++--------- .../Component/Form/Tests/SimpleFormTest.php | 17 +-- .../Form/Tests/Util/OrderedHashMapTest.php | 3 + .../HttpFoundation/Tests/IpUtilsTest.php | 8 +- .../Tests/RequestMatcherTest.php | 8 +- .../HttpFoundation/Tests/RequestTest.php | 51 ++++----- .../Tests/Session/SessionTest.php | 2 + .../Tests/Session/Storage/MetadataBagTest.php | 3 + .../Tests/StreamedResponseTest.php | 4 +- .../Acl/Tests/Dbal/MutableAclProviderTest.php | 39 ++++--- .../Domain/PermissionGrantingStrategyTest.php | 11 +- .../Encoder/BCryptPasswordEncoderTest.php | 17 ++- .../Core/Tests/LegacySecurityContextTest.php | 3 +- .../Http/Tests/Firewall/DigestDataTest.php | 13 ++- 27 files changed, 222 insertions(+), 150 deletions(-) create mode 100644 src/Symfony/Component/Config/Tests/Fixtures/BarNode.php diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php index 6456639af305e..63efd719b5f59 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php @@ -145,13 +145,16 @@ public function providePrototypedArrayNodeDefaults() public function testNestedPrototypedArrayNodes() { - $node = new ArrayNodeDefinition('root'); - $node + $nodeDefinition = new ArrayNodeDefinition('root'); + $nodeDefinition ->addDefaultChildrenIfNoneSet() ->prototype('array') ->prototype('array') ; - $node->getNode(); + $node = $nodeDefinition->getNode(); + + $this->assertInstanceOf('Symfony\Component\Config\Definition\PrototypedArrayNode', $node); + $this->assertInstanceOf('Symfony\Component\Config\Definition\PrototypedArrayNode', $node->getPrototype()); } public function testEnabledNodeDefaults() diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php index 16a10227cc296..13304fae36e95 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php @@ -71,6 +71,8 @@ public function testPrototypedArrayNodeUseTheCustomNodeBuilder() $root = $builder->root('override', 'array', new CustomNodeBuilder()); $root->prototype('bar')->end(); + + $this->assertInstanceOf('Symfony\Component\Config\Tests\Fixtures\BarNode', $root->getNode(true)->getPrototype()); } public function testAnExtendedNodeBuilderGetsPropagatedToTheChildren() @@ -79,7 +81,7 @@ public function testAnExtendedNodeBuilderGetsPropagatedToTheChildren() $builder->root('propagation') ->children() - ->setNodeClass('extended', 'Symfony\Component\Config\Tests\Definition\Builder\VariableNodeDefinition') + ->setNodeClass('extended', 'Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition') ->node('foo', 'extended')->end() ->arrayNode('child') ->children() @@ -88,6 +90,15 @@ public function testAnExtendedNodeBuilderGetsPropagatedToTheChildren() ->end() ->end() ->end(); + + $node = $builder->buildTree(); + $children = $node->getChildren(); + + $this->assertInstanceOf('Symfony\Component\Config\Definition\BooleanNode', $children['foo']); + + $childChildren = $children['child']->getChildren(); + + $this->assertInstanceOf('Symfony\Component\Config\Definition\BooleanNode', $childChildren['foo']); } public function testDefinitionInfoGetsTransferredToNode() diff --git a/src/Symfony/Component/Config/Tests/Fixtures/BarNode.php b/src/Symfony/Component/Config/Tests/Fixtures/BarNode.php new file mode 100644 index 0000000000000..0b9c32dedaf1f --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Fixtures/BarNode.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Config\Tests\Fixtures; + +use Symfony\Component\Config\Definition\ArrayNode; + +class BarNode extends ArrayNode +{ +} diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Builder/BarNodeDefinition.php b/src/Symfony/Component/Config/Tests/Fixtures/Builder/BarNodeDefinition.php index 47701c1b29eb8..0d46f3d2c8c01 100644 --- a/src/Symfony/Component/Config/Tests/Fixtures/Builder/BarNodeDefinition.php +++ b/src/Symfony/Component/Config/Tests/Fixtures/Builder/BarNodeDefinition.php @@ -12,10 +12,12 @@ namespace Symfony\Component\Config\Tests\Definition\Builder; use Symfony\Component\Config\Definition\Builder\NodeDefinition; +use Symfony\Component\Config\Tests\Fixtures\BarNode; class BarNodeDefinition extends NodeDefinition { protected function createNode() { + return new BarNode($this->name); } } diff --git a/src/Symfony/Component/Form/Tests/CompoundFormTest.php b/src/Symfony/Component/Form/Tests/CompoundFormTest.php index 3738a4c953c0c..b9b93e54c1637 100644 --- a/src/Symfony/Component/Form/Tests/CompoundFormTest.php +++ b/src/Symfony/Component/Form/Tests/CompoundFormTest.php @@ -299,6 +299,8 @@ public function testRemoveThrowsExceptionIfAlreadySubmitted() public function testRemoveIgnoresUnknownName() { $this->form->remove('notexisting'); + + $this->assertCount(0, $this->form); } public function testArrayAccess() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index 983397b09d624..3e36c7dd2936a 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -126,9 +126,9 @@ public function testChoiceLoaderOptionExpectsChoiceLoaderInterface() public function testChoiceListAndChoicesCanBeEmpty() { - $this->factory->create(static::TESTED_TYPE, null, array( + $this->assertInstanceOf('Symfony\Component\Form\FormInterface', $this->factory->create(static::TESTED_TYPE, null, array( 'choices_as_values' => true, - )); + ))); } public function testExpandedChoicesOptionsTurnIntoChildren() @@ -2251,10 +2251,10 @@ public function testAdjustFullNameForMultipleNonExpanded() // https://github.com/symfony/symfony/issues/3298 public function testInitializeWithEmptyChoices() { - $this->factory->createNamed('name', static::TESTED_TYPE, null, array( + $this->assertInstanceOf('Symfony\Component\Form\FormInterface', $this->factory->createNamed('name', static::TESTED_TYPE, null, array( 'choices' => array(), 'choices_as_values' => true, - )); + ))); } public function testInitializeWithDefaultObjectChoice() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php index 3d8e86defb39f..7765f4706d399 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CountryTypeTest.php @@ -43,11 +43,13 @@ public function testUnknownCountryIsNotIncluded() $choices = $this->factory->create(static::TESTED_TYPE, 'country') ->createView()->vars['choices']; + $countryCodes = array(); + foreach ($choices as $choice) { - if ('ZZ' === $choice->value) { - $this->fail('Should not contain choice "ZZ"'); - } + $countryCodes[] = $choice->value; } + + $this->assertNotContains('ZZ', $countryCodes); } public function testSubmitNull($expected = null, $norm = null, $view = null) diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php index dca17c3400223..9a80bdd87ba86 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php @@ -273,7 +273,7 @@ public function testInitializeWithDateTime() { // Throws an exception if "data_class" option is not explicitly set // to null in the type - $this->factory->create(static::TESTED_TYPE, new \DateTime()); + $this->assertInstanceOf('Symfony\Component\Form\FormInterface', $this->factory->create(static::TESTED_TYPE, new \DateTime())); } public function testSingleTextWidgetShouldUseTheRightInputType() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php index d907c9c3d15e2..7fcb1f505d337 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php @@ -711,7 +711,7 @@ public function testInitializeWithDateTime() { // Throws an exception if "data_class" option is not explicitly set // to null in the type - $this->factory->create(static::TESTED_TYPE, new \DateTime()); + $this->assertInstanceOf('Symfony\Component\Form\FormInterface', $this->factory->create(static::TESTED_TYPE, new \DateTime())); } public function testSingleTextWidgetShouldUseTheRightInputType() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index 5f5d5def6937b..1ff4057d5f373 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -149,23 +149,23 @@ public function testPassMaxLengthBCToView() public function testDataClassMayBeNull() { - $this->factory->createBuilder(static::TESTED_TYPE, null, array( + $this->assertInstanceOf('Symfony\Component\Form\FormBuilderInterface', $this->factory->createBuilder(static::TESTED_TYPE, null, array( 'data_class' => null, - )); + ))); } public function testDataClassMayBeAbstractClass() { - $this->factory->createBuilder(static::TESTED_TYPE, null, array( + $this->assertInstanceOf('Symfony\Component\Form\FormBuilderInterface', $this->factory->createBuilder(static::TESTED_TYPE, null, array( 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\AbstractAuthor', - )); + ))); } public function testDataClassMayBeInterface() { - $this->factory->createBuilder(static::TESTED_TYPE, null, array( + $this->assertInstanceOf('Symfony\Component\Form\FormBuilderInterface', $this->factory->createBuilder(static::TESTED_TYPE, null, array( 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\AuthorInterface', - )); + ))); } /** @@ -652,7 +652,7 @@ public function testCanGetErrorsWhenButtonInForm() $form = $builder->getForm(); //This method should not throw a Fatal Error Exception. - $form->getErrorsAsString(); + $this->assertInternalType('string', $form->getErrorsAsString()); } public function testSubmitNull($expected = null, $norm = null, $view = null) diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php index 8537c96fe049f..48fd5964db611 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php @@ -488,7 +488,7 @@ public function testInitializeWithDateTime() { // Throws an exception if "data_class" option is not explicitly set // to null in the type - $this->factory->create(static::TESTED_TYPE, new \DateTime()); + $this->assertInstanceOf('Symfony\Component\Form\FormInterface', $this->factory->create(static::TESTED_TYPE, new \DateTime())); } public function testSingleTextWidgetShouldUseTheRightInputType() diff --git a/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php index 22f3f9d8e3589..f04d092e878dd 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php @@ -46,16 +46,21 @@ public function testGetTypeExtensions() public function testThrowExceptionForInvalidExtendedType() { + $formTypeExtension = $this->createFormTypeExtensionMock('unmatched'); + $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock(); $container->expects($this->any()) ->method('get') ->with('extension') - ->willReturn($this->createFormTypeExtensionMock('unmatched')); + ->willReturn($formTypeExtension); $extension = new DependencyInjectionExtension($container, array(), array('test' => array('extension')), array()); - $extension->getTypeExtensions('test'); + $extensions = $extension->getTypeExtensions('test'); + + $this->assertCount(1, $extensions); + $this->assertSame($formTypeExtension, $extensions[0]); } public function testGetTypeGuesser() diff --git a/src/Symfony/Component/Form/Tests/FormBuilderTest.php b/src/Symfony/Component/Form/Tests/FormBuilderTest.php index fae2b1623dbf8..4f0a813ccd8bb 100644 --- a/src/Symfony/Component/Form/Tests/FormBuilderTest.php +++ b/src/Symfony/Component/Form/Tests/FormBuilderTest.php @@ -161,6 +161,8 @@ public function testAddButton() { $this->builder->add(new ButtonBuilder('reset')); $this->builder->add(new SubmitButtonBuilder('submit')); + + $this->assertCount(2, $this->builder->all()); } public function testGetUnknown() diff --git a/src/Symfony/Component/Form/Tests/FormConfigTest.php b/src/Symfony/Component/Form/Tests/FormConfigTest.php index 21eabba871d38..bb922bf3d61ff 100644 --- a/src/Symfony/Component/Form/Tests/FormConfigTest.php +++ b/src/Symfony/Component/Form/Tests/FormConfigTest.php @@ -12,9 +12,7 @@ namespace Symfony\Component\Form\Tests; use PHPUnit\Framework\TestCase; -use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\FormConfigBuilder; -use Symfony\Component\Form\Exception\InvalidArgumentException; /** * @author Bernhard Schussek @@ -24,72 +22,65 @@ class FormConfigTest extends TestCase public function getHtml4Ids() { return array( - array('z0', true), - array('A0', true), - array('A9', true), - array('Z0', true), - array('#', false), - array('a#', false), - array('a$', false), - array('a%', false), - array('a ', false), - array("a\t", false), - array("a\n", false), - array('a-', true), - array('a_', true), - array('a:', true), + array('z0'), + array('A0'), + array('A9'), + array('Z0'), + array('#', 'Symfony\Component\Form\Exception\InvalidArgumentException'), + array('a#', 'Symfony\Component\Form\Exception\InvalidArgumentException'), + array('a$', 'Symfony\Component\Form\Exception\InvalidArgumentException'), + array('a%', 'Symfony\Component\Form\Exception\InvalidArgumentException'), + array('a ', 'Symfony\Component\Form\Exception\InvalidArgumentException'), + array("a\t", 'Symfony\Component\Form\Exception\InvalidArgumentException'), + array("a\n", 'Symfony\Component\Form\Exception\InvalidArgumentException'), + array('a-'), + array('a_'), + array('a:'), // Periods are allowed by the HTML4 spec, but disallowed by us // because they break the generated property paths - array('a.', false), + array('a.', 'Symfony\Component\Form\Exception\InvalidArgumentException'), // Contrary to the HTML4 spec, we allow names starting with a // number, otherwise naming fields by collection indices is not // possible. // For root forms, leading digits will be stripped from the // "id" attribute to produce valid HTML4. - array('0', true), - array('9', true), + array('0'), + array('9'), // Contrary to the HTML4 spec, we allow names starting with an // underscore, since this is already a widely used practice in // Symfony. // For root forms, leading underscores will be stripped from the // "id" attribute to produce valid HTML4. - array('_', true), + array('_'), // Integers are allowed - array(0, true), - array(123, true), + array(0), + array(123), // NULL is allowed - array(null, true), + array(null), // Other types are not - array(1.23, false), - array(5., false), - array(true, false), - array(new \stdClass(), false), + array(1.23, 'Symfony\Component\Form\Exception\UnexpectedTypeException'), + array(5., 'Symfony\Component\Form\Exception\UnexpectedTypeException'), + array(true, 'Symfony\Component\Form\Exception\UnexpectedTypeException'), + array(new \stdClass(), 'Symfony\Component\Form\Exception\UnexpectedTypeException'), ); } /** * @dataProvider getHtml4Ids */ - public function testNameAcceptsOnlyNamesValidAsIdsInHtml4($name, $accepted) + public function testNameAcceptsOnlyNamesValidAsIdsInHtml4($name, $expectedException = null) { $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - try { - new FormConfigBuilder($name, null, $dispatcher); - if (!$accepted) { - $this->fail(sprintf('The value "%s" should not be accepted', $name)); - } - } catch (UnexpectedTypeException $e) { - // if the value was not accepted, but should be, rethrow exception - if ($accepted) { - throw $e; - } - } catch (InvalidArgumentException $e) { - // if the value was not accepted, but should be, rethrow exception - if ($accepted) { - throw $e; - } + if (null !== $expectedException && method_exists($this, 'expectException')) { + $this->expectException($expectedException); + } elseif (null !== $expectedException) { + $this->setExpectedException($expectedException); } + + $formConfigBuilder = new FormConfigBuilder($name, null, $dispatcher); + + $this->assertSame((string) $name, $formConfigBuilder->getName()); } public function testGetRequestHandlerCreatesNativeRequestHandlerIfNotSet() @@ -109,27 +100,42 @@ public function testGetRequestHandlerReusesNativeRequestHandlerInstance() public function testSetMethodAllowsGet() { - $this->getConfigBuilder()->setMethod('GET'); + $formConfigBuilder = $this->getConfigBuilder(); + $formConfigBuilder->setMethod('GET'); + + self::assertSame('GET', $formConfigBuilder->getMethod()); } public function testSetMethodAllowsPost() { - $this->getConfigBuilder()->setMethod('POST'); + $formConfigBuilder = $this->getConfigBuilder(); + $formConfigBuilder->setMethod('POST'); + + self::assertSame('POST', $formConfigBuilder->getMethod()); } public function testSetMethodAllowsPut() { - $this->getConfigBuilder()->setMethod('PUT'); + $formConfigBuilder = $this->getConfigBuilder(); + $formConfigBuilder->setMethod('PUT'); + + self::assertSame('PUT', $formConfigBuilder->getMethod()); } public function testSetMethodAllowsDelete() { - $this->getConfigBuilder()->setMethod('DELETE'); + $formConfigBuilder = $this->getConfigBuilder(); + $formConfigBuilder->setMethod('DELETE'); + + self::assertSame('DELETE', $formConfigBuilder->getMethod()); } public function testSetMethodAllowsPatch() { - $this->getConfigBuilder()->setMethod('PATCH'); + $formConfigBuilder = $this->getConfigBuilder(); + $formConfigBuilder->setMethod('PATCH'); + + self::assertSame('PATCH', $formConfigBuilder->getMethod()); } /** diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index 6223d3b39f95c..9d745e3edf81d 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -918,12 +918,11 @@ public function testSetDataCannotInvokeItself() public function testSubmittingWrongDataIsIgnored() { - $test = $this; + $called = 0; $child = $this->getBuilder('child', $this->dispatcher); - $child->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($test) { - // child form doesn't receive the wrong data that is submitted on parent - $test->assertNull($event->getData()); + $child->addEventListener(FormEvents::PRE_SUBMIT, function () use (&$called) { + ++$called; }); $parent = $this->getBuilder('parent', new EventDispatcher()) @@ -933,6 +932,8 @@ public function testSubmittingWrongDataIsIgnored() ->getForm(); $parent->submit('not-an-array'); + + $this->assertSame(0, $called, 'PRE_SUBMIT event listeners are not called for wrong data'); } public function testHandleRequestForwardsToRequestHandler() @@ -1036,15 +1037,17 @@ public function testPostSubmitDataIsNullIfInheritData() public function testSubmitIsNeverFiredIfInheritData() { - $test = $this; + $called = 0; $form = $this->getBuilder() - ->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) use ($test) { - $test->fail('The SUBMIT event should not be fired'); + ->addEventListener(FormEvents::SUBMIT, function () use (&$called) { + ++$called; }) ->setInheritData(true) ->getForm(); $form->submit('foo'); + + $this->assertSame(0, $called, 'The SUBMIT event is not fired when data are inherited from the parent form'); } public function testInitializeSetsDefaultData() diff --git a/src/Symfony/Component/Form/Tests/Util/OrderedHashMapTest.php b/src/Symfony/Component/Form/Tests/Util/OrderedHashMapTest.php index 4328919651efa..89735ea6180c6 100644 --- a/src/Symfony/Component/Form/Tests/Util/OrderedHashMapTest.php +++ b/src/Symfony/Component/Form/Tests/Util/OrderedHashMapTest.php @@ -114,8 +114,11 @@ public function testUnset() public function testUnsetNonExistingSucceeds() { $map = new OrderedHashMap(); + $map['second'] = 2; unset($map['first']); + + $this->assertSame(array('second' => 2), iterator_to_array($map)); } public function testEmptyIteration() diff --git a/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php b/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php index 61aa74861ddee..297ee3d8d3542 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php @@ -17,14 +17,14 @@ class IpUtilsTest extends TestCase { /** - * @dataProvider testIpv4Provider + * @dataProvider getIpv4Data */ public function testIpv4($matches, $remoteAddr, $cidr) { $this->assertSame($matches, IpUtils::checkIp($remoteAddr, $cidr)); } - public function testIpv4Provider() + public function getIpv4Data() { return array( array(true, '192.168.1.1', '192.168.1.1'), @@ -43,7 +43,7 @@ public function testIpv4Provider() } /** - * @dataProvider testIpv6Provider + * @dataProvider getIpv6Data */ public function testIpv6($matches, $remoteAddr, $cidr) { @@ -54,7 +54,7 @@ public function testIpv6($matches, $remoteAddr, $cidr) $this->assertSame($matches, IpUtils::checkIp($remoteAddr, $cidr)); } - public function testIpv6Provider() + public function getIpv6Data() { return array( array(true, '2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'), diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php index 6f864d4468fe7..b5d80048ff11e 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php @@ -18,7 +18,7 @@ class RequestMatcherTest extends TestCase { /** - * @dataProvider testMethodFixtures + * @dataProvider getMethodData */ public function testMethod($requestMethod, $matcherMethod, $isMatch) { @@ -32,7 +32,7 @@ public function testMethod($requestMethod, $matcherMethod, $isMatch) $this->assertSame($isMatch, $matcher->matches($request)); } - public function testMethodFixtures() + public function getMethodData() { return array( array('get', 'get', true), @@ -64,7 +64,7 @@ public function testScheme() } /** - * @dataProvider testHostFixture + * @dataProvider getHostData */ public function testHost($pattern, $isMatch) { @@ -78,7 +78,7 @@ public function testHost($pattern, $isMatch) $this->assertSame($isMatch, $matcher->matches($request)); } - public function testHostFixture() + public function getHostData() { return array( array('.*\.example\.com', true), diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 2d8baa7142e12..6f9d76b4835e0 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -306,6 +306,10 @@ public function testGetFormatFromMimeType($format, $mimeTypes) $request->setFormat($format, $mimeTypes); foreach ($mimeTypes as $mime) { $this->assertEquals($format, $request->getFormat($mime)); + + if (null !== $format) { + $this->assertEquals($mimeTypes[0], $request->getMimeType($format)); + } } } @@ -315,17 +319,6 @@ public function testGetFormatFromMimeTypeWithParameters() $this->assertEquals('json', $request->getFormat('application/json; charset=utf-8')); } - /** - * @dataProvider getFormatToMimeTypeMapProvider - */ - public function testGetMimeTypeFromFormat($format, $mimeTypes) - { - if (null !== $format) { - $request = new Request(); - $this->assertEquals($mimeTypes[0], $request->getMimeType($format)); - } - } - public function testGetFormatWithCustomMimeType() { $request = new Request(); @@ -821,7 +814,7 @@ public function testGetSetMethod() } /** - * @dataProvider testGetClientIpsProvider + * @dataProvider getClientIpsProvider */ public function testGetClientIp($expected, $remoteAddr, $httpForwardedFor, $trustedProxies) { @@ -833,7 +826,7 @@ public function testGetClientIp($expected, $remoteAddr, $httpForwardedFor, $trus } /** - * @dataProvider testGetClientIpsProvider + * @dataProvider getClientIpsProvider */ public function testGetClientIps($expected, $remoteAddr, $httpForwardedFor, $trustedProxies) { @@ -845,7 +838,7 @@ public function testGetClientIps($expected, $remoteAddr, $httpForwardedFor, $tru } /** - * @dataProvider testGetClientIpsForwardedProvider + * @dataProvider getClientIpsForwardedProvider */ public function testGetClientIpsForwarded($expected, $remoteAddr, $httpForwarded, $trustedProxies) { @@ -856,7 +849,7 @@ public function testGetClientIpsForwarded($expected, $remoteAddr, $httpForwarded Request::setTrustedProxies(array()); } - public function testGetClientIpsForwardedProvider() + public function getClientIpsForwardedProvider() { // $expected $remoteAddr $httpForwarded $trustedProxies return array( @@ -869,7 +862,7 @@ public function testGetClientIpsForwardedProvider() ); } - public function testGetClientIpsProvider() + public function getClientIpsProvider() { // $expected $remoteAddr $httpForwardedFor $trustedProxies return array( @@ -926,7 +919,7 @@ public function testGetClientIpsProvider() /** * @expectedException \Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException - * @dataProvider testGetClientIpsWithConflictingHeadersProvider + * @dataProvider getClientIpsWithConflictingHeadersProvider */ public function testGetClientIpsWithConflictingHeaders($httpForwarded, $httpXForwardedFor) { @@ -945,7 +938,7 @@ public function testGetClientIpsWithConflictingHeaders($httpForwarded, $httpXFor $request->getClientIps(); } - public function testGetClientIpsWithConflictingHeadersProvider() + public function getClientIpsWithConflictingHeadersProvider() { // $httpForwarded $httpXForwardedFor return array( @@ -958,9 +951,9 @@ public function testGetClientIpsWithConflictingHeadersProvider() } /** - * @dataProvider testGetClientIpsWithAgreeingHeadersProvider + * @dataProvider getClientIpsWithAgreeingHeadersProvider */ - public function testGetClientIpsWithAgreeingHeaders($httpForwarded, $httpXForwardedFor) + public function testGetClientIpsWithAgreeingHeaders($httpForwarded, $httpXForwardedFor, $expectedIps) { $request = new Request(); @@ -974,21 +967,23 @@ public function testGetClientIpsWithAgreeingHeaders($httpForwarded, $httpXForwar $request->initialize(array(), array(), array(), array(), array(), $server); - $request->getClientIps(); + $clientIps = $request->getClientIps(); Request::setTrustedProxies(array()); + + $this->assertSame($expectedIps, $clientIps); } - public function testGetClientIpsWithAgreeingHeadersProvider() + public function getClientIpsWithAgreeingHeadersProvider() { // $httpForwarded $httpXForwardedFor return array( - array('for="192.0.2.60"', '192.0.2.60'), - array('for=192.0.2.60, for=87.65.43.21', '192.0.2.60,87.65.43.21'), - array('for="[::face]", for=192.0.2.60', '::face,192.0.2.60'), - array('for="192.0.2.60:80"', '192.0.2.60'), - array('for=192.0.2.60;proto=http;by=203.0.113.43', '192.0.2.60'), - array('for="[2001:db8:cafe::17]:4711"', '2001:db8:cafe::17'), + array('for="192.0.2.60"', '192.0.2.60', array('192.0.2.60')), + array('for=192.0.2.60, for=87.65.43.21', '192.0.2.60,87.65.43.21', array('87.65.43.21', '192.0.2.60')), + array('for="[::face]", for=192.0.2.60', '::face,192.0.2.60', array('192.0.2.60', '::face')), + array('for="192.0.2.60:80"', '192.0.2.60', array('192.0.2.60')), + array('for=192.0.2.60;proto=http;by=203.0.113.43', '192.0.2.60', array('192.0.2.60')), + array('for="[2001:db8:cafe::17]:4711"', '2001:db8:cafe::17', array('2001:db8:cafe::17')), ); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php index 4d5d337a3c011..fa93507a41aaf 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/SessionTest.php @@ -177,6 +177,8 @@ public function testSave() { $this->session->start(); $this->session->save(); + + $this->assertFalse($this->session->isStarted()); } public function testGetId() diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MetadataBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MetadataBagTest.php index 1f55a2d5c440d..159e62114e1a3 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MetadataBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/MetadataBagTest.php @@ -103,6 +103,9 @@ public function testGetLastUsed() public function testClear() { $this->bag->clear(); + + // the clear method has no side effects, we just want to ensure it doesn't trigger any exceptions + $this->addToAssertionCount(1); } public function testSkipLastUsedUpdate() diff --git a/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php index 844274b1e7e21..5874145348eab 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php @@ -51,10 +51,12 @@ public function testPrepareWith10Protocol() public function testPrepareWithHeadRequest() { - $response = new StreamedResponse(function () { echo 'foo'; }); + $response = new StreamedResponse(function () { echo 'foo'; }, 200, array('Content-Length' => '123')); $request = Request::create('/', 'HEAD'); $response->prepare($request); + + $this->assertSame('123', $response->headers->get('Content-Length')); } public function testPrepareWithCacheHeaders() diff --git a/src/Symfony/Component/Security/Acl/Tests/Dbal/MutableAclProviderTest.php b/src/Symfony/Component/Security/Acl/Tests/Dbal/MutableAclProviderTest.php index e7de0b54875e2..f119168221959 100644 --- a/src/Symfony/Component/Security/Acl/Tests/Dbal/MutableAclProviderTest.php +++ b/src/Symfony/Component/Security/Acl/Tests/Dbal/MutableAclProviderTest.php @@ -19,8 +19,6 @@ use Symfony\Component\Security\Acl\Domain\Entry; use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; use Symfony\Component\Security\Acl\Domain\Acl; -use Symfony\Component\Security\Acl\Exception\AclNotFoundException; -use Symfony\Component\Security\Acl\Exception\ConcurrentModificationException; use Symfony\Component\Security\Acl\Dbal\AclProvider; use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy; use Symfony\Component\Security\Acl\Dbal\MutableAclProvider; @@ -79,23 +77,25 @@ public function testCreateAcl() $this->assertTrue($acl->getObjectIdentity()->equals($oid)); } + /** + * @expectedException \Symfony\Component\Security\Acl\Exception\AclNotFoundException + */ public function testDeleteAcl() { $provider = $this->getProvider(); $oid = new ObjectIdentity(1, 'Foo'); - $acl = $provider->createAcl($oid); + $provider->createAcl($oid); $provider->deleteAcl($oid); $loadedAcls = $this->getField($provider, 'loadedAcls'); $this->assertCount(0, $loadedAcls['Foo']); - try { - $provider->findAcl($oid); - $this->fail('ACL has not been properly deleted.'); - } catch (AclNotFoundException $e) { - } + $provider->findAcl($oid); } + /** + * @expectedException \Symfony\Component\Security\Acl\Exception\AclNotFoundException + */ public function testDeleteAclDeletesChildren() { $provider = $this->getProvider(); @@ -105,11 +105,7 @@ public function testDeleteAclDeletesChildren() $provider->updateAcl($acl); $provider->deleteAcl($parentAcl->getObjectIdentity()); - try { - $provider->findAcl(new ObjectIdentity(1, 'Foo')); - $this->fail('Child-ACLs have not been deleted.'); - } catch (AclNotFoundException $e) { - } + $provider->findAcl(new ObjectIdentity(1, 'Foo')); } public function testFindAclsAddsPropertyListener() @@ -273,6 +269,9 @@ public function testUpdateDoesNothingWhenThereAreNoChanges() $provider->updateAcl($acl); } + /** + * @expectedException \Symfony\Component\Security\Acl\Exception\ConcurrentModificationException + */ public function testUpdateAclThrowsExceptionOnConcurrentModificationOfSharedProperties() { $provider = $this->getProvider(); @@ -291,11 +290,7 @@ public function testUpdateAclThrowsExceptionOnConcurrentModificationOfSharedProp $acl1->insertClassAce($sid, 3); $acl2->insertClassAce($sid, 5); - try { - $provider->updateAcl($acl1); - $this->fail('Provider failed to detect a concurrent modification.'); - } catch (ConcurrentModificationException $e) { - } + $provider->updateAcl($acl1); } public function testUpdateAcl() @@ -366,7 +361,7 @@ public function testUpdateAclUpdatesChildAclsCorrectly() $this->assertEquals($newParentParentAcl->getId(), $reloadedAcl->getParentAcl()->getParentAcl()->getId()); } - public function testUpdateAclInsertingMultipleObjectFieldAcesThrowsDBConstraintViolations() + public function testUpdateAclInsertingMultipleObjectFieldAcesDoesNotThrowDBConstraintViolations() { $provider = $this->getProvider(); $oid = new ObjectIdentity(1, 'Foo'); @@ -386,9 +381,11 @@ public function testUpdateAclInsertingMultipleObjectFieldAcesThrowsDBConstraintV $acl = $provider->findAcl($oid); $acl->insertObjectFieldAce($fieldName, $sid3, 4); $provider->updateAcl($acl); + + $this->assertCount(3, $provider->findAcl($oid)->getObjectFieldAces($fieldName)); } - public function testUpdateAclDeletingObjectFieldAcesThrowsDBConstraintViolations() + public function testUpdateAclDeletingObjectFieldAcesDoesNotThrowDBConstraintViolations() { $provider = $this->getProvider(); $oid = new ObjectIdentity(1, 'Foo'); @@ -412,6 +409,8 @@ public function testUpdateAclDeletingObjectFieldAcesThrowsDBConstraintViolations $acl = $provider->findAcl($oid); $acl->insertObjectFieldAce($fieldName, $sid3, 4); $provider->updateAcl($acl); + + $this->assertCount(2, $provider->findAcl($oid)->getObjectFieldAces($fieldName)); } public function testUpdateUserSecurityIdentity() diff --git a/src/Symfony/Component/Security/Acl/Tests/Domain/PermissionGrantingStrategyTest.php b/src/Symfony/Component/Security/Acl/Tests/Domain/PermissionGrantingStrategyTest.php index f77262654f12b..abb89eceac9a0 100644 --- a/src/Symfony/Component/Security/Acl/Tests/Domain/PermissionGrantingStrategyTest.php +++ b/src/Symfony/Component/Security/Acl/Tests/Domain/PermissionGrantingStrategyTest.php @@ -17,7 +17,6 @@ use Symfony\Component\Security\Acl\Domain\Acl; use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy; -use Symfony\Component\Security\Acl\Exception\NoAceFoundException; class PermissionGrantingStrategyTest extends TestCase { @@ -152,11 +151,13 @@ public function testIsGrantedStrategies($maskStrategy, $aceMask, $requiredMask, $acl->insertObjectAce($sid, $aceMask, 0, true, $maskStrategy); if (false === $result) { - try { - $strategy->isGranted($acl, array($requiredMask), array($sid)); - $this->fail('The ACE is not supposed to match.'); - } catch (NoAceFoundException $e) { + if (method_exists($this, 'expectException')) { + $this->expectException('Symfony\Component\Security\Acl\Exception\NoAceFoundException'); + } else { + $this->setExpectedException('Symfony\Component\Security\Acl\Exception\NoAceFoundException'); } + + $strategy->isGranted($acl, array($requiredMask), array($sid)); } else { $this->assertTrue($strategy->isGranted($acl, array($requiredMask), array($sid))); } diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/BCryptPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/BCryptPasswordEncoderTest.php index 10c8da692a6fd..b6b6ab8c8015d 100644 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/BCryptPasswordEncoderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/BCryptPasswordEncoderTest.php @@ -39,11 +39,20 @@ public function testCostAboveRange() new BCryptPasswordEncoder(32); } - public function testCostInRange() + /** + * @dataProvider validRangeData + */ + public function testCostInRange($cost) + { + $this->assertInstanceOf('Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder', new BCryptPasswordEncoder($cost)); + } + + public function validRangeData() { - for ($cost = 4; $cost <= 31; ++$cost) { - new BCryptPasswordEncoder($cost); - } + $costs = range(4, 31); + array_walk($costs, function (&$cost) { $cost = array($cost); }); + + return $costs; } public function testResultLength() diff --git a/src/Symfony/Component/Security/Core/Tests/LegacySecurityContextTest.php b/src/Symfony/Component/Security/Core/Tests/LegacySecurityContextTest.php index 3661c7be95609..3c842aae76cef 100644 --- a/src/Symfony/Component/Security/Core/Tests/LegacySecurityContextTest.php +++ b/src/Symfony/Component/Security/Core/Tests/LegacySecurityContextTest.php @@ -86,7 +86,8 @@ public function testOldConstructorSignature() { $authenticationManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock(); $accessDecisionManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')->getMock(); - new SecurityContext($authenticationManager, $accessDecisionManager); + + $this->assertInstanceOf('Symfony\Component\Security\Core\SecurityContext', new SecurityContext($authenticationManager, $accessDecisionManager)); } /** diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/DigestDataTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/DigestDataTest.php index 2238a74188853..7317e2f83c7cc 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/DigestDataTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/DigestDataTest.php @@ -100,6 +100,9 @@ public function testGetUsernameWithEscape() $this->assertEquals('"u\\ser"', $digestAuth->getUsername()); } + /** + * @group time-sensitive + */ public function testValidateAndDecode() { $time = microtime(true); @@ -112,11 +115,11 @@ public function testValidateAndDecode() 'response="b52938fc9e6d7c01be7702ece9031b42"' ); - try { - $digestAuth->validateAndDecode($key, 'Welcome, robot!'); - } catch (\Exception $e) { - $this->fail(sprintf('testValidateAndDecode fail with message: %s', $e->getMessage())); - } + $digestAuth->validateAndDecode($key, 'Welcome, robot!'); + + sleep(1); + + $this->assertTrue($digestAuth->isNonceExpired()); } public function testCalculateServerDigest() From 2fe1631be8bed747c3993540c68f9aa5c38b9a2d Mon Sep 17 00:00:00 2001 From: insekticid Date: Tue, 4 Apr 2017 16:54:31 +0200 Subject: [PATCH 82/88] Allow Upper Case property names ReflectionExtractor::getProperties() returns $id instead of $Id. It is bad naming convention, but is possible ``` class Entity { protected $Id; public function getId() { return $this->Id; } } ``` # Conflicts: # src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php # src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php --- .../Extractor/ReflectionExtractor.php | 2 +- .../Extractors/ReflectionExtractorTest.php | 9 +++++++++ .../PropertyInfo/Tests/Fixtures/Dummy.php | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 0e7bb091adc80..8ba5db00d352b 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -76,7 +76,7 @@ public function getProperties($class, array $context = array()) if (!$propertyName || isset($properties[$propertyName])) { continue; } - if (!preg_match('/^[A-Z]{2,}/', $propertyName)) { + if (!$reflectionClass->hasProperty($propertyName) && !preg_match('/^[A-Z]{2,}/', $propertyName)) { $propertyName = lcfirst($propertyName); } $properties[$propertyName] = true; diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php index 6af92affe03d5..55f75b901671f 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php @@ -38,6 +38,7 @@ public function testGetProperties() 'parent', 'collection', 'B', + 'Guid', 'g', 'foo', 'foo2', @@ -47,6 +48,7 @@ public function testGetProperties() 'files', 'a', 'DOB', + 'Id', 'c', 'd', 'e', @@ -129,6 +131,10 @@ public function testIsReadable() $this->assertTrue($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'd', array())); $this->assertFalse($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'e', array())); $this->assertFalse($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'f', array())); + $this->assertTrue($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'Id', array())); + $this->assertTrue($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'id', array())); + $this->assertTrue($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'Guid', array())); + $this->assertFalse($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'guid', array())); } public function testIsWritable() @@ -142,5 +148,8 @@ public function testIsWritable() $this->assertFalse($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'd', array())); $this->assertTrue($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'e', array())); $this->assertTrue($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'f', array())); + $this->assertFalse($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'Id', array())); + $this->assertTrue($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'Guid', array())); + $this->assertFalse($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'guid', array())); } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php index 12065b18b62a3..2f6fc11b0de5a 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -51,6 +51,16 @@ class Dummy extends ParentDummy */ public $B; + /** + * @var int + */ + protected $Id; + + /** + * @var string + */ + public $Guid; + /** * Nullable array. * @@ -99,4 +109,11 @@ public function setB(ParentDummy $parent = null) public function getDOB() { } + + /** + * @return int + */ + public function getId() + { + } } From 6e1cee62b90e2b8e06fb531538d632dfcff48322 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Tue, 4 Apr 2017 16:31:24 +0200 Subject: [PATCH 83/88] [FrameworkBundle] Update console fixtures after #22217 --- .../FrameworkBundle/Tests/Fixtures/Descriptor/route_1.txt | 6 +++--- .../FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt | 6 +++--- src/Symfony/Bundle/FrameworkBundle/composer.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1.txt index 587543fb0a47f..ed0bcca6562eb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1.txt @@ -11,7 +11,7 @@ | Requirements | name: [a-z]+ | | Class | Symfony\Component\Routing\Route | | Defaults | name: Joseph | -| Options | compiler_class: Symfony\Component\Routing\RouteCompiler | -| | opt1: val1 | -| | opt2: val2 | +| Options | compiler_class: Symfony\Component\Routing\RouteCompiler | +| | opt1: val1 | +| | opt2: val2 | +--------------+---------------------------------------------------------+ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt index e75c19e13112c..828f6316bedb9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt @@ -11,7 +11,7 @@ | Requirements | NO CUSTOM | | Class | Symfony\Component\Routing\Route | | Defaults | NONE | -| Options | compiler_class: Symfony\Component\Routing\RouteCompiler | -| | opt1: val1 | -| | opt2: val2 | +| Options | compiler_class: Symfony\Component\Routing\RouteCompiler | +| | opt1: val1 | +| | opt2: val2 | +--------------+---------------------------------------------------------+ diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 1001174eb7b85..857c7271ccd4a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -38,7 +38,7 @@ }, "require-dev": { "symfony/browser-kit": "~2.4|~3.0.0", - "symfony/console": "~2.8.8|~3.0.8", + "symfony/console": "~2.8.19|~3.3", "symfony/css-selector": "^2.0.5|~3.0.0", "symfony/dom-crawler": "^2.0.5|~3.0.0", "symfony/polyfill-intl-icu": "~1.0", From 761d452162d988d8b5e07cacc231333374f6400a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 4 Apr 2017 21:00:33 +0200 Subject: [PATCH 84/88] fix merge --- .../Form/Tests/Extension/Core/Type/ChoiceTypeTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index bbad60dfb1041..15e08ae96f91e 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -102,9 +102,7 @@ public function testChoiceLoaderOptionExpectsChoiceLoaderInterface() public function testChoiceListAndChoicesCanBeEmpty() { - $this->assertInstanceOf('Symfony\Component\Form\FormInterface', $this->factory->create(static::TESTED_TYPE, null, array( - 'choices_as_values' => true, - ))); + $this->assertInstanceOf('Symfony\Component\Form\FormInterface', $this->factory->create(static::TESTED_TYPE, null, array())); } public function testExpandedChoicesOptionsTurnIntoChildren() From 6ecec3557ec6444ee0ce36c3ec92080c9ebe92b2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 5 Apr 2017 08:52:45 +0200 Subject: [PATCH 85/88] [HttpKernel] Fix forward compat with Request::setTrustedProxies() --- src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php | 2 +- src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php | 2 +- .../Tests/EventListener/ValidateRequestListenerTest.php | 2 +- .../Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php | 2 +- src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php index 51bddd1d9828c..444466764be57 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/WebProcessorTest.php @@ -36,7 +36,7 @@ public function testUsesRequestServerData() public function testUseRequestClientIp() { - Request::setTrustedProxies(array('192.168.0.1')); + Request::setTrustedProxies(array('192.168.0.1'), -1); list($event, $server) = $this->createRequestEvent(array('X_FORWARDED_FOR' => '192.168.0.2')); $processor = new WebProcessor(); diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index 686f0b852c202..297e98a240ac8 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -464,7 +464,7 @@ protected function forward(Request $request, $catch = false, Response $entry = n // make sure HttpCache is a trusted proxy if (!in_array('127.0.0.1', $trustedProxies = Request::getTrustedProxies())) { $trustedProxies[] = '127.0.0.1'; - Request::setTrustedProxies($trustedProxies); + Request::setTrustedProxies($trustedProxies, method_exists('Request', 'getTrustedHeaderSet') ? Request::getTrustedHeaderSet() : -1); } // always a "master" request (as the real master request can be in cache) diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php index 55dc59e13f716..d6ac73855763f 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ValidateRequestListenerTest.php @@ -30,7 +30,7 @@ public function testListenerThrowsWhenMasterRequestHasInconsistentClientIps() $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); $request = new Request(); - $request->setTrustedProxies(array('1.1.1.1')); + $request->setTrustedProxies(array('1.1.1.1'), -1); $request->server->set('REMOTE_ADDR', '1.1.1.1'); $request->headers->set('FORWARDED', 'for=2.2.2.2'); $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index f303ec37328d6..5e03bc7a2a878 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -1218,7 +1218,7 @@ public function testClientIpIsAlwaysLocalhostForForwardedRequests() */ public function testHttpCacheIsSetAsATrustedProxy(array $existing, array $expected) { - Request::setTrustedProxies($existing); + Request::setTrustedProxies($existing, -1); $this->setNextResponse(); $this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1')); diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php index 9f373c82fc488..74a808c15e897 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php @@ -309,7 +309,7 @@ public function testVerifyRequestStackPushPopDuringHandle() public function testInconsistentClientIpsOnMasterRequests() { $request = new Request(); - $request->setTrustedProxies(array('1.1.1.1')); + $request->setTrustedProxies(array('1.1.1.1'), -1); $request->server->set('REMOTE_ADDR', '1.1.1.1'); $request->headers->set('FORWARDED', 'for=2.2.2.2'); $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); From b878f7e62e0858eb30d9d7e3c1e5cea694c2024d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 5 Apr 2017 10:00:23 +0200 Subject: [PATCH 86/88] [Workflow] update documentation URL in readme --- src/Symfony/Component/Workflow/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Workflow/README.md b/src/Symfony/Component/Workflow/README.md index d0a1a4d3a9aef..068bd887689f2 100644 --- a/src/Symfony/Component/Workflow/README.md +++ b/src/Symfony/Component/Workflow/README.md @@ -4,7 +4,7 @@ Workflow Component Resources --------- - * [Documentation](https://symfony.com/doc/master/components/workflow.html) + * [Documentation](https://symfony.com/doc/current/components/workflow.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) From 1c18f34230a6ad592c7244bfb632613b13750a44 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 5 Apr 2017 05:51:48 -0700 Subject: [PATCH 87/88] updated CHANGELOG for 3.2.7 --- CHANGELOG-3.2.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/CHANGELOG-3.2.md b/CHANGELOG-3.2.md index 71a26930ea92b..93dc435ade79f 100644 --- a/CHANGELOG-3.2.md +++ b/CHANGELOG-3.2.md @@ -7,6 +7,51 @@ in 3.2 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.2.0...v3.2.1 +* 3.2.7 (2017-04-05) + + * bug #22285 [HttpKernel] Fix forward compat with Request::setTrustedProxies() (nicolas-grekas) + * bug #22265 Allow Upper Case property names (insekticid) + * bug #22258 [DI] Autowiring and factories are incompatible with each others (nicolas-grekas) + * bug #22254 [DI] Don't use auto-registered services to populate type-candidates (nicolas-grekas) + * bug #22229 [ExpressionLanguage] Provide the expression in syntax errors (k0pernikus, stof) + * bug #22251 [PropertyInfo] Support nullable array or collection (4rthem) + * bug #22240 [DI] Fix fatal error at ContainerBuilder::compile() if config is not installed (chalasr) + * bug #22140 [Form] Improve the exceptions when trying to get the data in a PRE_SET_DATA listener and the data has not already been set (fancyweb) + * bug #22217 [Console] Fix table cell styling (ro0NL) + * bug #22194 [Console] CommandTester: disable color support detection (julienfalque) + * bug #22188 [Console] Revised exception rendering (ro0NL) + * bug #22154 [WebProfilerBundle] Normalize whitespace in exceptions passed in headers (curry684) + * bug #22183 [Process] Fix bug which wiped or mangled env vars (pjcdawkins) + * bug #22142 [Console] Escape exception messages in renderException (chalasr) + * bug #22172 Fix port usage in server:status command (alcaeus) + * bug #22164 [Bridge\Doctrine] Fix change breaking doctrine-bundle test suite (nicolas-grekas) + * bug #22159 [FrameworkBundle] Cache pool clear command requires at least 1 pool (ro0NL) + * bug #22133 [Filesystem] normalize paths before making them relative (xabbuh) + * bug #22138 [HttpFoundation][bugfix] $bags should always be initialized (MacDada) + * bug #21810 #21809 [SecurityBundle] bugfix: if security provider's name contains upper cases then container didn't compile (Antanas Arvasevicius) + * bug #22123 [WebProfilerBundle] Fix for CSS attribute at Profiler Translation Page (e-moe) + * bug #19778 [Security] Fixed roles serialization on token from user object (eko) + * bug #22036 Set Date header in Response constructor already (mpdude) + * bug #22022 [Validator] fix URL validator to detect non supported chars according to RFC 3986 (e-moe) + * bug #21849 [HttpFoundation] Fix missing handling of for/host/proto info from "Forwarded" header (nicolas-grekas) + * bug #21968 Fixed pathinfo calculation for requests starting with a question mark. (syzygymsu) + * bug #22027 Revert "bug #21841 [Console] Do not squash input changes made from console.command event (chalasr)" (chalasr) + * bug #21846 [HttpFoundation] Fix Request::getHost() when having several hosts in X_FORWARDED_HOST (nicolas-grekas) + * bug #21208 [Validator] Add object handling of invalid constraints in Composite (SenseException) + * bug #22044 [Serializer] [XML] Ignore Process Instruction (jordscream) + * bug #22090 [WebProfilerBundle] Fix Content-Security-Policy compatibility in case of a `style-src 'self'` policy (romainneutron) + * bug #22079 [HttpKernel] Fixed bug with purging of HTTPS URLs (ausi) + * bug #22045 [WebProfilerBundle] Handle Content-Security-Policy-Report-Only header correctly (romainneutron) + * bug #21523 #20411 fix Yaml parsing for very long quoted strings (RichardBradley) + * bug #22001 [Doctrine Bridge] fix priority for doctrine event listeners (dmaicher) + * bug #22040 [FrameworkBundle] improve message when workflows are missing (xabbuh) + * bug #22032 [FrameworkBundle] Fix translation dep constraint (chalasr) + * bug #21996 [Cache] Enhance error reporting for FilesystemAdapter (nicolas-grekas) + * bug #21981 [Console] Use proper line endings in BufferedOutput (julienfalque) + * bug #21976 [VarDumper] Add missing isset() checks in some casters (nicolas-grekas) + * bug #21973 [VarDumper] Add missing isset() checks in some casters (nicolas-grekas) + * bug #21957 [Form] Choice type int values (BC Fix) (mcfedr) + * 3.2.6 (2017-03-10) * bug #21930 [Cache] Cached files rely on umask (4rthem) From 98313d4c7bdea3f46d2ac30682192466b8739383 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 5 Apr 2017 05:52:03 -0700 Subject: [PATCH 88/88] updated VERSION for 3.2.7 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index d056a43acc37e..3bff41d941456 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '3.2.7-DEV'; + const VERSION = '3.2.7'; const VERSION_ID = 30207; const MAJOR_VERSION = 3; const MINOR_VERSION = 2; const RELEASE_VERSION = 7; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '07/2017'; const END_OF_LIFE = '01/2018';