From 534d9fc560a1d25b30148debae80a752cae4bc55 Mon Sep 17 00:00:00 2001 From: Jakub Zalas Date: Wed, 22 Jul 2015 09:03:09 +0100 Subject: [PATCH 01/16] [Console] Fix console output with closed stdout --- .../Console/Output/ConsoleOutput.php | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Console/Output/ConsoleOutput.php b/src/Symfony/Component/Console/Output/ConsoleOutput.php index 708d171445..50ef4df900 100644 --- a/src/Symfony/Component/Console/Output/ConsoleOutput.php +++ b/src/Symfony/Component/Console/Output/ConsoleOutput.php @@ -46,12 +46,9 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface */ public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null) { - $outputStream = $this->hasStdoutSupport() ? 'php://stdout' : 'php://output'; - $errorStream = $this->hasStderrSupport() ? 'php://stderr' : 'php://output'; + parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter); - parent::__construct(fopen($outputStream, 'w'), $verbosity, $decorated, $formatter); - - $this->stderr = new StreamOutput(fopen($errorStream, 'w'), $verbosity, $decorated, $this->getFormatter()); + $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter()); } /** @@ -129,4 +126,24 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface { return 'OS400' === php_uname('s'); } + + /** + * @return resource + */ + private function openOutputStream() + { + $outputStream = $this->hasStdoutSupport() ? 'php://stdout' : 'php://output'; + + return @fopen($outputStream, 'w') ?: fopen('php://output', 'w'); + } + + /** + * @return resource + */ + private function openErrorStream() + { + $errorStream = $this->hasStderrSupport() ? 'php://stderr' : 'php://output'; + + return fopen($errorStream, 'w'); + } } From 445774592920ecd9a1e752f3c447507f11193805 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Fri, 3 Jul 2015 00:05:34 +0200 Subject: [PATCH 02/16] Implement resettable containers This allows to remove references to all services during shutdown, giving much more chances to destruct services and the container through refcounting rather than waiting GC, as it will break cycles between the container and container-aware services. --- .../DependencyInjection/CHANGELOG.md | 1 + .../DependencyInjection/Container.php | 15 ++++++- .../ResettableContainerInterface.php | 31 +++++++++++++ .../Tests/ContainerTest.php | 43 +++++++++++++++++++ src/Symfony/Component/HttpKernel/Kernel.php | 5 +++ 5 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/DependencyInjection/ResettableContainerInterface.php diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 7c4ff51e8c..c13da0b280 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -7,6 +7,7 @@ CHANGELOG * allowed specifying a directory to recursively load all configuration files it contains * deprecated the concept of scopes * added `Definition::setShared()` and `Definition::isShared()` + * added ResettableContainerInterface to be able to reset the container to release memory on shutdown 2.7.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 0222d7063b..513fc9de0f 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection; use Symfony\Component\DependencyInjection\Exception\InactiveScopeException; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; @@ -60,7 +61,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; * * @api */ -class Container implements IntrospectableContainerInterface +class Container implements IntrospectableContainerInterface, ResettableContainerInterface { /** * @var ParameterBagInterface @@ -375,6 +376,18 @@ class Container implements IntrospectableContainerInterface return isset($this->services[$id]) || array_key_exists($id, $this->services); } + /** + * {@inheritdoc} + */ + public function reset() + { + if (!empty($this->scopedServices)) { + throw new LogicException('Resetting the container is not allowed when a scope is active.'); + } + + $this->services = array(); + } + /** * Gets all service ids. * diff --git a/src/Symfony/Component/DependencyInjection/ResettableContainerInterface.php b/src/Symfony/Component/DependencyInjection/ResettableContainerInterface.php new file mode 100644 index 0000000000..b74e676245 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/ResettableContainerInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection; + +/** + * ResettableContainerInterface defines additional resetting functionality + * for containers, allowing to release shared services when the container is + * not needed anymore. + * + * @author Christophe Coevoet + */ +interface ResettableContainerInterface extends ContainerInterface +{ + /** + * Resets shared services from the container. + * + * The container is not intended to be used again after being reset in a normal workflow. This method is + * meant as a way to release references for ref-counting. + * A subsequent call to ContainerInterface::get will recreate a new instance of the shared service. + */ + public function reset(); +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php index 09b4a12e2f..cffef39008 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php @@ -320,6 +320,49 @@ class ContainerTest extends \PHPUnit_Framework_TestCase $this->assertTrue($sc->initialized('alias'), '->initialized() returns true for alias if aliased service is initialized'); } + public function testReset() + { + $c = new Container(); + $c->set('bar', new \stdClass()); + + $c->reset(); + + $this->assertNull($c->get('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE)); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException + * @expectedExceptionMessage Resetting the container is not allowed when a scope is active. + * @group legacy + */ + public function testCannotResetInActiveScope() + { + $c = new Container(); + $c->addScope(new Scope('foo')); + $c->set('bar', new \stdClass()); + + $c->enterScope('foo'); + + $c->reset(); + } + + /** + * @group legacy + */ + public function testResetAfterLeavingScope() + { + $c = new Container(); + $c->addScope(new Scope('foo')); + $c->set('bar', new \stdClass()); + + $c->enterScope('foo'); + $c->leaveScope('foo'); + + $c->reset(); + + $this->assertNull($c->get('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE)); + } + /** * @group legacy */ diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 5f714d97d5..d70439bd08 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -23,6 +23,7 @@ use Symfony\Component\DependencyInjection\Loader\IniFileLoader; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\DependencyInjection\Loader\DirectoryLoader; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; +use Symfony\Component\DependencyInjection\ResettableContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Bundle\BundleInterface; @@ -180,6 +181,10 @@ abstract class Kernel implements KernelInterface, TerminableInterface $bundle->setContainer(null); } + if ($this->container instanceof ResettableContainerInterface) { + $this->container->reset(); + } + $this->container = null; } From d3874eca2cdbd1d3e915e1666c6f4aff9f93390e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 22 Jul 2015 13:57:38 +0200 Subject: [PATCH 03/16] [travis] Tests deps=low with PHP 5.6 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a780aa1d61..b27111e496 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,6 @@ matrix: - php: 5.4 - php: 5.5 - php: 5.6 - - php: 5.3 env: deps=low - php: 5.6 env: deps=high From 1fc03155d4fd869ac629e91c49862122c7a1e389 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Wed, 22 Jul 2015 15:05:05 +0200 Subject: [PATCH 04/16] [Security] removed useless else condition in SwitchUserListener class. --- .../Component/Security/Http/Firewall/SwitchUserListener.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index c5ecf780f5..79b715aa3c 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -116,9 +116,9 @@ class SwitchUserListener implements ListenerInterface if (false !== $originalToken) { if ($token->getUsername() === $request->get($this->usernameParameter)) { return $token; - } else { - throw new \LogicException(sprintf('You are already switched to "%s" user.', $token->getUsername())); } + + throw new \LogicException(sprintf('You are already switched to "%s" user.', $token->getUsername())); } if (false === $this->accessDecisionManager->decide($token, array($this->role))) { From ebb20640af518a39133b1098a03436dd4e0568f4 Mon Sep 17 00:00:00 2001 From: WouterJ Date: Sun, 28 Jun 2015 14:36:46 +0200 Subject: [PATCH 05/16] [Security] Moved Simple{Form,Pre}AuthenticatorInterfaces to Security\Http --- src/Symfony/Component/Security/CHANGELOG.md | 4 ++++ .../SimpleFormAuthenticatorInterface.php | 2 ++ .../SimplePreAuthenticatorInterface.php | 2 ++ .../SimpleFormAuthenticatorInterface.php | 21 +++++++++++++++++++ .../SimplePreAuthenticatorInterface.php | 21 +++++++++++++++++++ 5 files changed, 50 insertions(+) create mode 100644 src/Symfony/Component/Security/Http/Authentication/SimpleFormAuthenticatorInterface.php create mode 100644 src/Symfony/Component/Security/Http/Authentication/SimplePreAuthenticatorInterface.php diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 2b601a575f..f202692929 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -6,6 +6,10 @@ CHANGELOG * deprecated `getKey()` of the `AnonymousToken`, `RememberMeToken` and `AbstractRememberMeServices` classes in favor of `getSecret()`. + * deprecated `Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface`, use + `Symfony\Component\Security\Http\Authentication\SimplePreAuthenticatorInterface` instead + * deprecated `Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface`, use + `Symfony\Component\Security\Http\Authentication\SimpleFormAuthenticatorInterface` instead 2.7.0 ----- diff --git a/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php index 95ee881c18..ae2b58b19f 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimpleFormAuthenticatorInterface.php @@ -14,6 +14,8 @@ namespace Symfony\Component\Security\Core\Authentication; use Symfony\Component\HttpFoundation\Request; /** + * @deprecated Deprecated since version 2.8, to be removed in 3.0. Use the same interface from Security\Http\Authentication instead. + * * @author Jordi Boggiano */ interface SimpleFormAuthenticatorInterface extends SimpleAuthenticatorInterface diff --git a/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php b/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php index 6164e7d986..c01f064765 100644 --- a/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/SimplePreAuthenticatorInterface.php @@ -14,6 +14,8 @@ namespace Symfony\Component\Security\Core\Authentication; use Symfony\Component\HttpFoundation\Request; /** + * @deprecated Since version 2.8, to be removed in 3.0. Use the same interface from Security\Http\Authentication instead. + * * @author Jordi Boggiano */ interface SimplePreAuthenticatorInterface extends SimpleAuthenticatorInterface diff --git a/src/Symfony/Component/Security/Http/Authentication/SimpleFormAuthenticatorInterface.php b/src/Symfony/Component/Security/Http/Authentication/SimpleFormAuthenticatorInterface.php new file mode 100644 index 0000000000..112688c97c --- /dev/null +++ b/src/Symfony/Component/Security/Http/Authentication/SimpleFormAuthenticatorInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Authentication; + +use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface as BaseSimpleFormAuthenticatorInterface; + +/** + * @author Jordi Boggiano + */ +interface SimpleFormAuthenticatorInterface extends BaseSimpleFormAuthenticatorInterface +{ +} diff --git a/src/Symfony/Component/Security/Http/Authentication/SimplePreAuthenticatorInterface.php b/src/Symfony/Component/Security/Http/Authentication/SimplePreAuthenticatorInterface.php new file mode 100644 index 0000000000..afa8049508 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Authentication/SimplePreAuthenticatorInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Authentication; + +use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface as BaseSimplePreAuthenticatorInterface; + +/** + * @author Jordi Boggiano + */ +interface SimplePreAuthenticatorInterface extends BaseSimplePreAuthenticatorInterface +{ +} From 5ef7ae9647a7992dc2c8e6efd7003b6a50f56625 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 22 Jul 2015 19:02:20 +0200 Subject: [PATCH 06/16] [Form] Fix not-BC test assertion --- .../AbstractConstraintValidatorTest.php | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/AbstractConstraintValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/AbstractConstraintValidatorTest.php index 2204fedcd7..5a5fa51a0a 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/AbstractConstraintValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/AbstractConstraintValidatorTest.php @@ -216,24 +216,14 @@ abstract class AbstractConstraintValidatorTest extends \PHPUnit_Framework_TestCa protected function expectValidateAt($i, $propertyPath, $value, $group) { - switch ($this->getApiVersion()) { - case Validation::API_VERSION_2_4: - $this->context->expects($this->at($i)) - ->method('validate') - ->with($value, $propertyPath, $group); - break; - case Validation::API_VERSION_2_5: - case Validation::API_VERSION_2_5_BC: - $validator = $this->context->getValidator()->inContext($this->context); - $validator->expects($this->at(2 * $i)) - ->method('atPath') - ->with($propertyPath) - ->will($this->returnValue($validator)); - $validator->expects($this->at(2 * $i + 1)) - ->method('validate') - ->with($value, $this->logicalOr(null, array(), $this->isInstanceOf('\Symfony\Component\Validator\Constraints\Valid')), $group); - break; - } + $validator = $this->context->getValidator()->inContext($this->context); + $validator->expects($this->at(2 * $i)) + ->method('atPath') + ->with($propertyPath) + ->will($this->returnValue($validator)); + $validator->expects($this->at(2 * $i + 1)) + ->method('validate') + ->with($value, $this->logicalOr(null, array(), $this->isInstanceOf('\Symfony\Component\Validator\Constraints\Valid')), $group); } protected function expectValidateValueAt($i, $propertyPath, $value, $constraints, $group = null) From 65e9f268fea48a814c938890e05a3fdfd102b776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 22 Jul 2015 21:42:44 +0200 Subject: [PATCH 07/16] [Serializer] Fix bugs reported in https://github.com/symfony/symfony/commit/b5990be49149501bef7bb83a797a1aea2eb5fbe0#commitcomment-12301266 --- .../Normalizer/AbstractNormalizer.php | 2 +- .../Normalizer/GetSetMethodNormalizer.php | 3 +- .../Normalizer/GetSetMethodNormalizerTest.php | 50 ++++++++++++++++++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 4de4771770..93dfba9a39 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -291,7 +291,7 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N * * @throws RuntimeException */ - protected function instantiateObject(array $data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes) + protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes) { if ( isset($context['object_to_populate']) && diff --git a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php index de4c3ece1d..44a71cf1b4 100644 --- a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php @@ -102,6 +102,7 @@ class GetSetMethodNormalizer extends AbstractNormalizer $reflectionClass = new \ReflectionClass($class); $object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes); + $classMethods = get_class_methods($object); foreach ($normalizedData as $attribute => $value) { if ($this->nameConverter) { $attribute = $this->nameConverter->denormalize($attribute); @@ -113,7 +114,7 @@ class GetSetMethodNormalizer extends AbstractNormalizer if ($allowed && !$ignored) { $setter = 'set'.ucfirst($attribute); - if (method_exists($object, $setter)) { + if (in_array($setter, $classMethods)) { $object->$setter($value); } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php index 92051863d5..32d729a211 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -228,6 +228,12 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase $this->assertEquals('bar', $obj->getBar()); } + public function testConstructorWArgWithPrivateMutator() + { + $obj = $this->normalizer->denormalize(array('foo' => 'bar'), __NAMESPACE__.'\ObjectConstructorArgsWithPrivateMutatorDummy', 'any'); + $this->assertEquals('bar', $obj->getFoo()); + } + public function testGroupsNormalize() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); @@ -511,8 +517,8 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase public function testDenormalizeNonExistingAttribute() { $this->assertEquals( - new PropertyDummy(), - $this->normalizer->denormalize(array('non_existing' => true), __NAMESPACE__.'\PropertyDummy') + new GetSetDummy(), + $this->normalizer->denormalize(array('non_existing' => true), __NAMESPACE__.'\GetSetDummy') ); } @@ -520,6 +526,12 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase { $this->assertFalse($this->normalizer->supportsNormalization(new \ArrayObject())); } + + public function testPrivateSetter() + { + $obj = $this->normalizer->denormalize(array('foo' => 'foobar'), __NAMESPACE__.'\ObjectWithPrivateSetterDummy'); + $this->assertEquals('bar', $obj->getFoo()); + } } class GetSetDummy @@ -726,3 +738,37 @@ class GetCamelizedDummy return $this->bar_foo; } } + +class ObjectConstructorArgsWithPrivateMutatorDummy +{ + private $foo; + + public function __construct($foo) + { + $this->setFoo($foo); + } + + public function getFoo() + { + return $this->foo; + } + + private function setFoo($foo) + { + $this->foo = $foo; + } +} + +class ObjectWithPrivateSetterDummy +{ + private $foo = 'bar'; + + public function getFoo() + { + return $this->foo; + } + + private function setFoo($foo) + { + } +} From 2d29ac1e1093ac0e8b37cacc10d283ff97b87828 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 22 Jul 2015 18:52:24 +0200 Subject: [PATCH 08/16] [Security/Http] Fix test relying on a private property --- .../Tests/Firewall/AnonymousAuthenticationListenerTest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php index 3bc4eb66d8..9af4791974 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php @@ -54,10 +54,9 @@ class AnonymousAuthenticationListenerTest extends \PHPUnit_Framework_TestCase $authenticationManager ->expects($this->once()) ->method('authenticate') - ->with(self::logicalAnd( - $this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\AnonymousToken'), - $this->attributeEqualTo('key', 'TheKey') - )) + ->with($this->callback(function ($token) { + return 'TheKey' === $token->getKey(); + })) ->will($this->returnValue($anonymousToken)) ; From 37a235394ec277c97b660444e00212a13b59febe Mon Sep 17 00:00:00 2001 From: Vladimir Reznichenko Date: Mon, 20 Jul 2015 23:51:01 +0200 Subject: [PATCH 09/16] [2.6] Static Code Analysis for Components --- src/Symfony/Component/HttpKernel/Client.php | 2 +- src/Symfony/Component/Intl/Resources/bin/update-data.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Client.php b/src/Symfony/Component/HttpKernel/Client.php index 0503f5de58..50895e713d 100644 --- a/src/Symfony/Component/HttpKernel/Client.php +++ b/src/Symfony/Component/HttpKernel/Client.php @@ -101,7 +101,7 @@ class Client extends BaseClient $r = new \ReflectionClass('\\Symfony\\Component\\ClassLoader\\ClassLoader'); $requirePath = str_replace("'", "\\'", $r->getFileName()); - $symfonyPath = str_replace("'", "\\'", realpath(__DIR__.'/../../..')); + $symfonyPath = str_replace("'", "\\'", dirname(dirname(dirname(__DIR__)))); $errorReporting = error_reporting(); $code = << Date: Thu, 23 Jul 2015 11:09:02 +0200 Subject: [PATCH 10/16] [Twig+FrameworkBundle] Fix forward compat with Form 2.8 --- .../Resources/views/Form/form_div_layout.html.twig | 2 +- .../Extension/FormExtensionBootstrap3LayoutTest.php | 10 ++++++++++ .../Tests/Extension/FormExtensionDivLayoutTest.php | 10 ++++++++++ .../Tests/Extension/FormExtensionTableLayoutTest.php | 10 ++++++++++ .../Resources/views/Form/widget_attributes.html.php | 2 +- .../Templating/Helper/FormHelperDivLayoutTest.php | 10 ++++++++++ .../Templating/Helper/FormHelperTableLayoutTest.php | 10 ++++++++++ 7 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 48a432e41a..a0828b3800 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -314,7 +314,7 @@ {%- block widget_attributes -%} id="{{ id }}" name="{{ full_name }}" - {%- if read_only %} readonly="readonly"{% endif -%} + {%- if read_only and attr.readonly is not defined %} readonly="readonly"{% endif -%} {%- if disabled %} disabled="disabled"{% endif -%} {%- if required %} required="required"{% endif -%} {%- for attrname, attrvalue in attr -%} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php index 8e76552697..a9d161b2b9 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php @@ -115,4 +115,14 @@ class FormExtensionBootstrap3LayoutTest extends AbstractBootstrap3LayoutTest { $this->extension->renderer->setTheme($view, $themes); } + + public function testRange() + { + // No-op for forward compatibility with AbstractLayoutTest 2.8 + } + + public function testRangeWithMinMaxValues() + { + // 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 2581144a1c..1bce43b837 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -208,4 +208,14 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest array(array('parent_label.html.twig'), array('child_label.html.twig')), ); } + + public function testRange() + { + // No-op for forward compatibility with AbstractLayoutTest 2.8 + } + + public function testRangeWithMinMaxValues() + { + // 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 f8f3ddf3e5..555ea306fc 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php @@ -116,4 +116,14 @@ class FormExtensionTableLayoutTest extends AbstractTableLayoutTest { $this->extension->renderer->setTheme($view, $themes); } + + public function testRange() + { + // No-op for forward compatibility with AbstractLayoutTest 2.8 + } + + public function testRangeWithMinMaxValues() + { + // No-op for forward compatibility with AbstractLayoutTest 2.8 + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php index 118e764c85..14e65a7991 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget_attributes.html.php @@ -1,4 +1,4 @@ -id="escape($id) ?>" name="escape($full_name) ?>" readonly="readonly" +id="escape($id) ?>" name="escape($full_name) ?>" readonly="readonly" disabled="disabled" required="required" $v): ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php index 52d91ec127..4af5b929cb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @@ -128,4 +128,14 @@ class FormHelperDivLayoutTest extends AbstractDivLayoutTest array(array('TestBundle:Parent'), array('TestBundle:Child')), ); } + + public function testRange() + { + // No-op for forward compatibility with AbstractLayoutTest 2.8 + } + + public function testRangeWithMinMaxValues() + { + // 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 4a5c025c6d..1bf641fe1b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @@ -115,4 +115,14 @@ class FormHelperTableLayoutTest extends AbstractTableLayoutTest { $this->engine->get('form')->setTheme($view, $themes); } + + public function testRange() + { + // No-op for forward compatibility with AbstractLayoutTest 2.8 + } + + public function testRangeWithMinMaxValues() + { + // No-op for forward compatibility with AbstractLayoutTest 2.8 + } } From a1772b6a23e847d60bdd54db66cb7539a9260db8 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Sat, 25 Jul 2015 14:51:32 +0300 Subject: [PATCH 11/16] [Asset] removed unused private property. --- src/Symfony/Component/Asset/UrlPackage.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Component/Asset/UrlPackage.php b/src/Symfony/Component/Asset/UrlPackage.php index 0e9f82d0fa..6381a9c1cd 100644 --- a/src/Symfony/Component/Asset/UrlPackage.php +++ b/src/Symfony/Component/Asset/UrlPackage.php @@ -36,7 +36,6 @@ use Symfony\Component\Asset\Exception\LogicException; class UrlPackage extends Package { private $baseUrls = array(); - private $sslUrls; private $sslPackage; /** @@ -62,7 +61,7 @@ class UrlPackage extends Package $sslUrls = $this->getSslUrls($baseUrls); if ($sslUrls && $baseUrls !== $sslUrls) { - $this->sslPackage = new UrlPackage($sslUrls, $versionStrategy); + $this->sslPackage = new self($sslUrls, $versionStrategy); } } From e3914460f377b0e5f94a5d3028c5914139c5210b Mon Sep 17 00:00:00 2001 From: Vincent AUBERT Date: Fri, 24 Jul 2015 21:28:02 +0200 Subject: [PATCH 12/16] #15331 add infos about deprecated classes to UPGRADE-3.0 --- UPGRADE-3.0.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index f8dcd0b5e4..c819bc8987 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -272,6 +272,17 @@ UPGRADE FROM 2.x to 3.0 ```php echo $form->getErrors(true, false); ``` + * The `Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList` class has been removed in + favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`. + + * The `Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList` class has been removed in + favor of `Symfony\Component\Form\ChoiceList\LazyChoiceList`. + + * The `Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList` class has been removed in + favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`. + + * The `Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList` class has been removed in + favor of `Symfony\Component\Form\ChoiceList\ArrayChoiceList`. ### FrameworkBundle From aa7cbbd2053f56564450313d5d2e763df17a2a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20S=C3=A1nchez?= Date: Wed, 22 Jul 2015 16:34:23 -0300 Subject: [PATCH 13/16] Introduce failing test case when a SplFileInfo object is passed to the extract() method in the TwigExtractor. The problem is that when there's a twig error, symfony expects the `getRelativePath` method that the native object doesn't have. --- .../Twig/Tests/Translation/TwigExtractorTest.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php index 94ac80d884..f2b15fc5da 100644 --- a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php @@ -74,14 +74,26 @@ class TwigExtractorTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Twig_Error * @expectedExceptionMessageRegExp /Unclosed "block" in "extractor(\/|\\)syntax_error\.twig" at line 1/ + * @dataProvider resourcesWithSyntaxErrorsProvider */ - public function testExtractSyntaxError() + public function testExtractSyntaxError($resources) { $twig = new \Twig_Environment(new \Twig_Loader_Array(array())); $twig->addExtension(new TranslationExtension($this->getMock('Symfony\Component\Translation\TranslatorInterface'))); $extractor = new TwigExtractor($twig); - $extractor->extract(__DIR__.'/../Fixtures', new MessageCatalogue('en')); + $extractor->extract($resources, new MessageCatalogue('en')); + } + + /** + * @return array + */ + public function resourcesWithSyntaxErrorsProvider() + { + return array( + array(__DIR__.'/../Fixtures'), + array(new \SplFileInfo(__DIR__.'/../Fixtures/extractor/syntax_error.twig')), + ); } /** From 2bf78e5f20d0d6ce60e052c9dcb0ae31da604305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20S=C3=A1nchez?= Date: Thu, 23 Jul 2015 09:53:04 -0300 Subject: [PATCH 14/16] Resources as string have the same problem --- src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php index f2b15fc5da..fb860ec2ad 100644 --- a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php @@ -92,6 +92,7 @@ class TwigExtractorTest extends \PHPUnit_Framework_TestCase { return array( array(__DIR__.'/../Fixtures'), + array(__DIR__.'/../Fixtures/extractor/syntax_error.twig'), array(new \SplFileInfo(__DIR__.'/../Fixtures/extractor/syntax_error.twig')), ); } From 1e15761ac722e2459ebc775025e33f22cc996cc1 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 26 Jul 2015 08:27:26 +0200 Subject: [PATCH 15/16] [TwigBridge] type-dependent path discovery With the introduction of the `AbstractFileExtractor` in Symfony 2.7, the `extract()` method in the `TwigExtractor` class does not necessarily deal with `SplFileInfo` instances from the Finder component, but also receives `\SplFileInfo` objects initialized by the base extractor class. --- .../Bridge/Twig/Tests/Translation/TwigExtractorTest.php | 2 +- src/Symfony/Bridge/Twig/Translation/TwigExtractor.php | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php index fb860ec2ad..610d5a6068 100644 --- a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php @@ -73,7 +73,7 @@ class TwigExtractorTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Twig_Error - * @expectedExceptionMessageRegExp /Unclosed "block" in "extractor(\/|\\)syntax_error\.twig" at line 1/ + * @expectedExceptionMessageRegExp /Unclosed "block" in ".*extractor(\/|\\)syntax_error\.twig" at line 1/ * @dataProvider resourcesWithSyntaxErrorsProvider */ public function testExtractSyntaxError($resources) diff --git a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php index ad3fd9fe33..d892fe7303 100644 --- a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php +++ b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Twig\Translation; use Symfony\Component\Finder\Finder; +use Symfony\Component\Finder\SplFileInfo; use Symfony\Component\Translation\Extractor\AbstractFileExtractor; use Symfony\Component\Translation\Extractor\ExtractorInterface; use Symfony\Component\Translation\MessageCatalogue; @@ -60,7 +61,11 @@ class TwigExtractor extends AbstractFileExtractor implements ExtractorInterface try { $this->extractTemplate(file_get_contents($file->getPathname()), $catalogue); } catch (\Twig_Error $e) { - $e->setTemplateFile($file->getRelativePathname()); + if ($file instanceof SplFileInfo) { + $e->setTemplateFile($file->getRelativePathname()); + } elseif ($file instanceof \SplFileInfo) { + $e->setTemplateFile($file->getRealPath()); + } throw $e; } From adc6b3067da4a677204833a17894d108018ca6bc Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 22 Jul 2015 08:30:32 +0200 Subject: [PATCH 16/16] [Yaml] throw a ParseException on invalid data type Without this check, PHP would trigger a warning when an array was passed to `trim()`. The parser must throw a `ParseException` instance on a malformed YAML string instead. --- src/Symfony/Component/Yaml/Parser.php | 2 +- src/Symfony/Component/Yaml/Tests/ParserTest.php | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index cd5e1dc571..311ef18a37 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -234,7 +234,7 @@ class Parser } // 1-liner optionally followed by newline(s) - if ($this->lines[0] === trim($value)) { + if (is_string($value) && $this->lines[0] === trim($value)) { try { $value = Inline::parse($this->lines[0], $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs); } catch (ParseException $e) { diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 6e39e7dc66..f434d5585d 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -551,6 +551,21 @@ EOF ); } + /** + * @expectedException \Symfony\Component\Yaml\Exception\ParseException + * @expectedExceptionMessage missing colon + */ + public function testScalarInSequence() + { + Yaml::parse(<< It is an error for two equal keys to appear in the same mapping node. * > In such a case the YAML processor may continue, ignoring the second