From 834f55026345ffc220995091b2095c6651ec38dd Mon Sep 17 00:00:00 2001 From: Mathieu Lemoine Date: Fri, 13 May 2016 15:34:52 -0400 Subject: [PATCH 01/17] [DX][DI] Make Autowiring exceptions more future friendly --- .../Compiler/AutowirePass.php | 15 +++++--- .../Tests/Compiler/AutowirePassTest.php | 37 ++++++++++--------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index e4457d4608..a7812fe03d 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -225,13 +225,16 @@ class AutowirePass implements CompilerPassInterface private function createAutowiredDefinition(\ReflectionClass $typeHint, $id) { if (isset($this->notGuessableTypes[$typeHint->name])) { - throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Several services implementing this type have been declared: "%s".', $typeHint->name, $id, implode('", "', $this->types[$typeHint->name]))); + $classOrInterface = $typeHint->isInterface() ? 'interface' : 'class'; + $matchingServices = implode(', ', $this->types[$typeHint->name]); + + throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices)); + } - $noAvailableDefinitionMessage = sprintf('Unable to autowire argument of type "%s" for the service "%s". This type cannot be instantiated automatically and no service implementing this type is declared.', $typeHint->name, $id); - if (!$typeHint->isInstantiable()) { - throw new RuntimeException($noAvailableDefinitionMessage); + $classOrInterface = $typeHint->isInterface() ? 'interface' : 'class'; + 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); @@ -244,7 +247,9 @@ class AutowirePass implements CompilerPassInterface try { $this->completeDefinition($argumentId, $argumentDefinition); } catch (RuntimeException $e) { - throw new RuntimeException($noAvailableDefinitionMessage, 0, $e); + $classOrInterface = $typeHint->isInterface() ? 'interface' : 'class'; + $message = 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); + throw new RuntimeException($message, 0, $e); } return new Reference($argumentId); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 6098d9a913..b5badc31fd 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -103,7 +103,7 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Several services implementing this type have been declared: "c1", "c2". + * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (c1, c2, c3). */ public function testTypeCollision() { @@ -111,6 +111,7 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase $container->register('c1', __NAMESPACE__.'\CollisionA'); $container->register('c2', __NAMESPACE__.'\CollisionB'); + $container->register('c3', __NAMESPACE__.'\CollisionB'); $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); $aDefinition->setAutowired(true); @@ -120,7 +121,7 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "a". Several services implementing this type have been declared: "a1", "a2". + * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "a". Multiple services exist for this class (a1, a2). */ public function testTypeNotGuessable() { @@ -137,7 +138,7 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\A" for the service "a". Several services implementing this type have been declared: "a1", "a2". + * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\A" for the service "a". Multiple services exist for this class (a1, a2). */ public function testTypeNotGuessableWithSubclass() { @@ -152,6 +153,21 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase $pass->process($container); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". No services were found matching this interface and it cannot be auto-registered. + */ + public function testTypeNotGuessableNoServicesFound() + { + $container = new ContainerBuilder(); + + $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + $aDefinition->setAutowired(true); + + $pass = new AutowirePass(); + $pass->process($container); + } + public function testTypeNotGuessableWithTypeSet() { $container = new ContainerBuilder(); @@ -207,21 +223,6 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase $this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass()); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". This type cannot be instantiated automatically and no service implementing this type is declared. - */ - public function testCreateNonInstanciable() - { - $container = new ContainerBuilder(); - - $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - public function testResolveParameter() { $container = new ContainerBuilder(); From 7d9e74e340134e3288b8d11525e8319ba592af99 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 14 May 2016 13:17:24 +0200 Subject: [PATCH 02/17] remove methods that were needed for PHP 5.3 --- .../Console/Helper/ProgressIndicator.php | 42 ++----------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/ProgressIndicator.php b/src/Symfony/Component/Console/Helper/ProgressIndicator.php index ccf9771bcf..f90a85c291 100644 --- a/src/Symfony/Component/Console/Helper/ProgressIndicator.php +++ b/src/Symfony/Component/Console/Helper/ProgressIndicator.php @@ -76,42 +76,6 @@ class ProgressIndicator $this->display(); } - /** - * Gets the current indicator message. - * - * @return string|null - * - * @internal for PHP 5.3 compatibility - */ - public function getMessage() - { - return $this->message; - } - - /** - * Gets the progress bar start time. - * - * @return int The progress bar start time - * - * @internal for PHP 5.3 compatibility - */ - public function getStartTime() - { - return $this->startTime; - } - - /** - * Gets the current animated indicator character. - * - * @return string - * - * @internal for PHP 5.3 compatibility - */ - public function getCurrentValue() - { - return $this->indicatorValues[$this->indicatorCurrent % count($this->indicatorValues)]; - } - /** * Starts the indicator output. * @@ -294,13 +258,13 @@ class ProgressIndicator { return array( 'indicator' => function (ProgressIndicator $indicator) { - return $indicator->getCurrentValue(); + return $indicator->indicatorValues[$indicator->indicatorCurrent % count($indicator->indicatorValues)]; }, 'message' => function (ProgressIndicator $indicator) { - return $indicator->getMessage(); + return $indicator->message; }, 'elapsed' => function (ProgressIndicator $indicator) { - return Helper::formatTime(time() - $indicator->getStartTime()); + return Helper::formatTime(time() - $indicator->startTime); }, 'memory' => function () { return Helper::formatMemory(memory_get_usage(true)); From f8dd87d7cc2e9c2551322662fb3d9bed7f332d3c Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Sat, 2 Apr 2016 12:30:41 +0200 Subject: [PATCH 03/17] [WebProfilerBundle] Fix CORS ajax security issues --- .../Resources/views/Profiler/base_js.html.twig | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index 8c10c95655..d9f92ca26a 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -80,6 +80,20 @@ requestStack = [], + extractHeaders = function(xhr, stackElement) { + // Here we avoid to call xhr.getResponseHeader in order to + // prevent polluting the console with CORS security errors + var allHeaders = xhr.getAllResponseHeaders(); + var ret; + + if (ret = allHeaders.match(/^x-debug-token:\s+(.*)$/im)) { + stackElement.profile = ret[1]; + } + if (ret = allHeaders.match(/^x-debug-token-link:\s+(.*)$/im)) { + stackElement.profilerUrl = ret[1]; + } + }, + renderAjaxRequests = function() { var requestCounter = document.querySelectorAll('.sf-toolbar-ajax-requests'); if (!requestCounter.length) { @@ -239,8 +253,8 @@ stackElement.duration = new Date() - stackElement.start; stackElement.loading = false; stackElement.error = self.status < 200 || self.status >= 400; - stackElement.profile = self.getResponseHeader("X-Debug-Token"); - stackElement.profilerUrl = self.getResponseHeader("X-Debug-Token-Link"); + + extractHeaders(self, stackElement); Sfjs.renderAjaxRequests(); } From ac7f74eccac01ce7b279c41b72f1422e575e67f6 Mon Sep 17 00:00:00 2001 From: Jeremy Benoist Date: Tue, 17 May 2016 14:52:22 +0200 Subject: [PATCH 04/17] Use levenshtein level for better Bundle matching --- .../Controller/ControllerNameParser.php | 1 + .../Tests/Controller/ControllerNameParserTest.php | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerNameParser.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerNameParser.php index 873c736841..374d0eba10 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerNameParser.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerNameParser.php @@ -142,6 +142,7 @@ class ControllerNameParser $lev = levenshtein($nonExistentBundleName, $bundleName); if ($lev <= strlen($nonExistentBundleName) / 3 && ($alternative === null || $lev < $shortest)) { $alternative = $bundleName; + $shortest = $lev; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerNameParserTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerNameParserTest.php index 4718c1eb0b..0fe47b0908 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerNameParserTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerNameParserTest.php @@ -59,8 +59,8 @@ class ControllerNameParserTest extends TestCase { $parser = $this->createParser(); - $this->assertEquals('FooBundle:Default:index', $parser->build('TestBundle\FooBundle\Controller\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string'); - $this->assertEquals('FooBundle:Sub\Default:index', $parser->build('TestBundle\FooBundle\Controller\Sub\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string'); + $this->assertEquals('FoooooBundle:Default:index', $parser->build('TestBundle\FooBundle\Controller\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string'); + $this->assertEquals('FoooooBundle:Sub\Default:index', $parser->build('TestBundle\FooBundle\Controller\Sub\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string'); try { $parser->build('TestBundle\FooBundle\Controller\DefaultController::index'); @@ -132,8 +132,9 @@ class ControllerNameParserTest extends TestCase public function getInvalidBundleNameTests() { return array( - array('FoodBundle:Default:index', 'FooBundle:Default:index'), - array('CrazyBundle:Default:index', false), + 'Alternative will be found using levenshtein' => array('FoodBundle:Default:index', 'FooBundle:Default:index'), + 'Alternative will be found using partial match' => array('FabpotFooBund:Default:index', 'FabpotFooBundle:Default:index'), + 'Bundle does not exist at all' => array('CrazyBundle:Default:index', false), ); } @@ -162,6 +163,7 @@ class ControllerNameParserTest extends TestCase $bundles = array( 'SensioFooBundle' => $this->getBundle('TestBundle\Fabpot\FooBundle', 'FabpotFooBundle'), 'SensioCmsFooBundle' => $this->getBundle('TestBundle\Sensio\Cms\FooBundle', 'SensioCmsFooBundle'), + 'FoooooBundle' => $this->getBundle('TestBundle\FooBundle', 'FoooooBundle'), 'FooBundle' => $this->getBundle('TestBundle\FooBundle', 'FooBundle'), 'FabpotFooBundle' => $this->getBundle('TestBundle\Fabpot\FooBundle', 'FabpotFooBundle'), ); From 187b64561586b81a0c8896328826cbe5dcb51e5a Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 17 May 2016 18:47:41 +0200 Subject: [PATCH 05/17] [FrameworkBundle] update upgrade instructions --- UPGRADE-3.0.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 8925b91189..327a36bf93 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -636,6 +636,11 @@ UPGRADE FROM 2.x to 3.0 be removed in Symfony 3.0. Use the `debug:config`, `debug:container`, `debug:router`, `debug:translation` and `lint:yaml` commands instead. + * The base `Controller`class is now abstract. + + * The visibility of all methods of the base `Controller` class has been changed from + `public` to `protected`. + * The `getRequest` method of the base `Controller` class has been deprecated since Symfony 2.4 and must be therefore removed in 3.0. The only reliable way to get the `Request` object is to inject it in the action method. From f49659f1372d4bfc9d9616f92c316e4cc5fd8726 Mon Sep 17 00:00:00 2001 From: Krzysiek Piasecki Date: Thu, 12 May 2016 08:29:24 +0200 Subject: [PATCH 06/17] [Validator] Support for DateTimeImmutable --- .../Component/Validator/Constraints/DateTimeValidator.php | 2 +- .../Component/Validator/Constraints/DateValidator.php | 2 +- .../Validator/Tests/Constraints/DateTimeValidatorTest.php | 7 +++++++ .../Validator/Tests/Constraints/DateValidatorTest.php | 7 +++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php index 8d82bd8ca9..0a867a7d4b 100644 --- a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php @@ -30,7 +30,7 @@ class DateTimeValidator extends DateValidator throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\DateTime'); } - if (null === $value || '' === $value || $value instanceof \DateTime) { + if (null === $value || '' === $value || $value instanceof \DateTimeInterface) { return; } diff --git a/src/Symfony/Component/Validator/Constraints/DateValidator.php b/src/Symfony/Component/Validator/Constraints/DateValidator.php index bfeb5fca30..ed836de9ac 100644 --- a/src/Symfony/Component/Validator/Constraints/DateValidator.php +++ b/src/Symfony/Component/Validator/Constraints/DateValidator.php @@ -47,7 +47,7 @@ class DateValidator extends ConstraintValidator throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Date'); } - if (null === $value || '' === $value || $value instanceof \DateTime) { + if (null === $value || '' === $value || $value instanceof \DateTimeInterface) { return; } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/DateTimeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/DateTimeValidatorTest.php index ebb1f3e6b7..dbc4d1aa68 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/DateTimeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/DateTimeValidatorTest.php @@ -42,6 +42,13 @@ class DateTimeValidatorTest extends AbstractConstraintValidatorTest $this->assertNoViolation(); } + public function testDateTimeImmutableClassIsValid() + { + $this->validator->validate(new \DateTimeImmutable(), new DateTime()); + + $this->assertNoViolation(); + } + /** * @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException */ diff --git a/src/Symfony/Component/Validator/Tests/Constraints/DateValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/DateValidatorTest.php index 67bb2340c3..ec62de6281 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/DateValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/DateValidatorTest.php @@ -42,6 +42,13 @@ class DateValidatorTest extends AbstractConstraintValidatorTest $this->assertNoViolation(); } + public function testDateTimeImmutableClassIsValid() + { + $this->validator->validate(new \DateTimeImmutable(), new Date()); + + $this->assertNoViolation(); + } + /** * @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException */ From 2718a6c764416ede6afa87fe4aaa28a480b93091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rouven=20We=C3=9Fling?= Date: Sat, 30 Apr 2016 12:40:11 +0200 Subject: [PATCH 07/17] [DependencyInjection] Avoid generating call_user_func in more cases --- .../DependencyInjection/Dumper/PhpDumper.php | 8 +++ .../Tests/Fixtures/containers/container9.php | 18 +++++ .../Tests/Fixtures/graphviz/services9.dot | 4 ++ .../Tests/Fixtures/php/services19.php | 2 +- .../Tests/Fixtures/php/services9.php | 68 +++++++++++++++++++ .../Tests/Fixtures/php/services9_compiled.php | 32 +++++++++ .../Tests/Fixtures/xml/services9.xml | 12 ++++ .../Tests/Fixtures/yaml/services9.yml | 14 ++++ 8 files changed, 157 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index e0a763dfe8..ba7fa385d8 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -537,6 +537,10 @@ class PhpDumper extends Dumper return sprintf(" %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $callable[1], $variableName); } + if (0 === strpos($class, 'new ')) { + return sprintf(" (%s)->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName); + } + return sprintf(" call_user_func(array(%s, '%s'), \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName); } @@ -713,6 +717,10 @@ EOF; return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : ''); } + if (0 === strpos($class, 'new ')) { + return sprintf(" $return{$instantiation}(%s)->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); + } + return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : ''); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php index 96f334fdd1..f499635604 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php @@ -78,6 +78,15 @@ $container ->register('configured_service', 'stdClass') ->setConfigurator(array(new Reference('configurator_service'), 'configureStdClass')) ; +$container + ->register('configurator_service_simple', 'ConfClass') + ->addArgument('bar') + ->setPublic(false) +; +$container + ->register('configured_service_simple', 'stdClass') + ->setConfigurator(array(new Reference('configurator_service_simple'), 'configureStdClass')) +; $container ->register('decorated', 'stdClass') ; @@ -111,5 +120,14 @@ $container ->register('service_from_static_method', 'Bar\FooClass') ->setFactory(array('Bar\FooClass', 'getInstance')) ; +$container + ->register('factory_simple', 'SimpleFactoryClass') + ->addArgument('foo') + ->setPublic(false) +; +$container + ->register('factory_service_simple', 'Bar') + ->setFactory(array(new Reference('factory_simple'), 'getInstance')) +; return $container; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot index f6536980aa..3b24ef8ffb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/graphviz/services9.dot @@ -14,6 +14,8 @@ digraph sc { node_request [label="request\nRequest\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_configurator_service [label="configurator_service\nConfClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_configured_service [label="configured_service\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; + node_configurator_service_simple [label="configurator_service_simple\nConfClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; + node_configured_service_simple [label="configured_service_simple\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_decorated [label="decorated\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_decorator_service [label="decorator_service\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_decorator_service_with_name [label="decorator_service_with_name\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; @@ -22,6 +24,8 @@ digraph sc { node_factory_service [label="factory_service\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_new_factory_service [label="new_factory_service\nFooBarBaz\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_service_from_static_method [label="service_from_static_method\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; + node_factory_simple [label="factory_simple\nSimpleFactoryClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; + node_factory_service_simple [label="factory_service_simple\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"]; node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"]; node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"]; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php index cc2a18dcd1..6c56cfcebf 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services19.php @@ -40,7 +40,7 @@ class ProjectServiceContainer extends Container */ protected function getServiceFromAnonymousFactoryService() { - return $this->services['service_from_anonymous_factory'] = call_user_func(array(new \Bar\FooClass(), 'getInstance')); + return $this->services['service_from_anonymous_factory'] = (new \Bar\FooClass())->getInstance(); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php index a29f7dd768..cb84452bca 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php @@ -28,12 +28,16 @@ class ProjectServiceContainer extends Container 'bar' => 'getBarService', 'baz' => 'getBazService', 'configurator_service' => 'getConfiguratorServiceService', + 'configurator_service_simple' => 'getConfiguratorServiceSimpleService', 'configured_service' => 'getConfiguredServiceService', + 'configured_service_simple' => 'getConfiguredServiceSimpleService', 'decorated' => 'getDecoratedService', 'decorator_service' => 'getDecoratorServiceService', 'decorator_service_with_name' => 'getDecoratorServiceWithNameService', 'deprecated_service' => 'getDeprecatedServiceService', 'factory_service' => 'getFactoryServiceService', + 'factory_service_simple' => 'getFactoryServiceSimpleService', + 'factory_simple' => 'getFactorySimpleService', 'foo' => 'getFooService', 'foo.baz' => 'getFoo_BazService', 'foo_bar' => 'getFooBarService', @@ -104,6 +108,23 @@ class ProjectServiceContainer extends Container return $instance; } + /** + * Gets the 'configured_service_simple' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \stdClass A stdClass instance. + */ + protected function getConfiguredServiceSimpleService() + { + $this->services['configured_service_simple'] = $instance = new \stdClass(); + + $this->get('configurator_service_simple')->configureStdClass($instance); + + return $instance; + } + /** * Gets the 'decorated' service. * @@ -173,6 +194,19 @@ class ProjectServiceContainer extends Container return $this->services['factory_service'] = $this->get('foo.baz')->getInstance(); } + /** + * Gets the 'factory_service_simple' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Bar A Bar instance. + */ + protected function getFactoryServiceSimpleService() + { + return $this->services['factory_service_simple'] = $this->get('factory_simple')->getInstance(); + } + /** * Gets the 'foo' service. * @@ -334,6 +368,40 @@ class ProjectServiceContainer extends Container return $instance; } + /** + * Gets the 'configurator_service_simple' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \ConfClass A ConfClass instance. + */ + protected function getConfiguratorServiceSimpleService() + { + return $this->services['configurator_service_simple'] = new \ConfClass('bar'); + } + + /** + * Gets the 'factory_simple' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \SimpleFactoryClass A SimpleFactoryClass instance. + */ + protected function getFactorySimpleService() + { + return $this->services['factory_simple'] = new \SimpleFactoryClass('foo'); + } + /** * Gets the 'inlined' service. * diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php index 5386b12a99..4fd1ac90f3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php @@ -30,10 +30,12 @@ class ProjectServiceContainer extends Container 'bar' => 'getBarService', 'baz' => 'getBazService', 'configured_service' => 'getConfiguredServiceService', + 'configured_service_simple' => 'getConfiguredServiceSimpleService', 'decorator_service' => 'getDecoratorServiceService', 'decorator_service_with_name' => 'getDecoratorServiceWithNameService', 'deprecated_service' => 'getDeprecatedServiceService', 'factory_service' => 'getFactoryServiceService', + 'factory_service_simple' => 'getFactoryServiceSimpleService', 'foo' => 'getFooService', 'foo.baz' => 'getFoo_BazService', 'foo_bar' => 'getFooBarService', @@ -114,6 +116,23 @@ class ProjectServiceContainer extends Container return $instance; } + /** + * Gets the 'configured_service_simple' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \stdClass A stdClass instance. + */ + protected function getConfiguredServiceSimpleService() + { + $this->services['configured_service_simple'] = $instance = new \stdClass(); + + (new \ConfClass('bar'))->configureStdClass($instance); + + return $instance; + } + /** * Gets the 'decorator_service' service. * @@ -170,6 +189,19 @@ class ProjectServiceContainer extends Container return $this->services['factory_service'] = $this->get('foo.baz')->getInstance(); } + /** + * Gets the 'factory_service_simple' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Bar A Bar instance. + */ + protected function getFactoryServiceSimpleService() + { + return $this->services['factory_service_simple'] = (new \SimpleFactoryClass('foo'))->getInstance(); + } + /** * Gets the 'foo' service. * diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml index 4ddb8655c5..d3974c07b0 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml @@ -84,6 +84,12 @@ + + bar + + + + @@ -103,6 +109,12 @@ + + foo + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml index 6efeb37e74..4a97dcadff 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml @@ -67,6 +67,13 @@ services: configured_service: class: stdClass configurator: ['@configurator_service', configureStdClass] + configurator_service_simple: + class: ConfClass + public: false + arguments: ['bar'] + configured_service_simple: + class: stdClass + configurator: ['@configurator_service_simple', configureStdClass] decorated: class: stdClass decorator_service: @@ -93,5 +100,12 @@ services: service_from_static_method: class: Bar\FooClass factory: [Bar\FooClass, getInstance] + factory_simple: + class: SimpleFactoryClass + public: false + arguments: ['foo'] + factory_service_simple: + class: Bar + factory: ['@factory_simple', getInstance] alias_for_foo: '@foo' alias_for_alias: '@foo' From 103526b40f6cfc46ad2f627e4e19c8f02cc08276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Proch=C3=A1zka?= Date: Thu, 12 May 2016 17:11:08 +0200 Subject: [PATCH 08/17] Catch \Throwable --- src/Symfony/Component/Debug/DebugClassLoader.php | 4 ++++ src/Symfony/Component/Debug/ErrorHandler.php | 6 ++++++ src/Symfony/Component/OptionsResolver/OptionsResolver.php | 6 ++++++ src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php | 2 ++ 4 files changed, 18 insertions(+) diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php index 36afa36930..603c814b56 100644 --- a/src/Symfony/Component/Debug/DebugClassLoader.php +++ b/src/Symfony/Component/Debug/DebugClassLoader.php @@ -175,6 +175,10 @@ class DebugClassLoader } catch (\Exception $e) { ErrorHandler::unstackErrors(); + throw $e; + } catch (\Throwable $e) { + ErrorHandler::unstackErrors(); + throw $e; } diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index 33779af325..9c30ffea44 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -447,6 +447,10 @@ class ErrorHandler } catch (\Exception $e) { $this->isRecursive = false; + throw $e; + } catch (\Throwable $e) { + $this->isRecursive = false; + throw $e; } } @@ -555,6 +559,8 @@ class ErrorHandler } } catch (\Exception $exception) { // Handled below + } catch (\Throwable $exception) { + // Handled below } if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) { diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index e0578af717..bc763202f2 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -861,6 +861,9 @@ class OptionsResolver implements Options, OptionsResolverInterface } catch (\Exception $e) { unset($this->calling[$option]); throw $e; + } catch (\Throwable $e) { + unset($this->calling[$option]); + throw $e; } unset($this->calling[$option]); // END @@ -963,6 +966,9 @@ class OptionsResolver implements Options, OptionsResolverInterface } catch (\Exception $e) { unset($this->calling[$option]); throw $e; + } catch (\Throwable $e) { + unset($this->calling[$option]); + throw $e; } unset($this->calling[$option]); // END diff --git a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php index cc4b2ef498..1035bd70c2 100644 --- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php @@ -141,6 +141,8 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface $this->dumpLine(-1); } catch (\Exception $exception) { // Re-thrown below + } catch (\Throwable $exception) { + // Re-thrown below } if ($output) { $this->setOutput($prevOutput); From de671f4cb2299f46fdbbd43e3bc747e813b0a90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Proch=C3=A1zka?= Date: Thu, 12 May 2016 17:11:08 +0200 Subject: [PATCH 09/17] Catch \Throwable --- .../Component/DependencyInjection/Compiler/AutowirePass.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index e4457d4608..7bb0516dc0 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -44,8 +44,8 @@ class AutowirePass implements CompilerPassInterface $this->completeDefinition($id, $definition); } } - } catch (\Error $e) { } catch (\Exception $e) { + } catch (\Throwable $e) { } spl_autoload_unregister($throwingAutoloader); From 3234ca491c20f3b173448115838056ac284b8c80 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 19 May 2016 21:50:23 +0200 Subject: [PATCH 10/17] fix removed commands wording in upgrade file --- UPGRADE-3.0.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 35823d8aaf..aef162311c 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -1604,8 +1604,7 @@ UPGRADE FROM 2.x to 3.0 ### WebProfiler - * The `profiler:import` and `profiler:export` commands have been deprecated and - will be removed in 3.0. + * The `profiler:import` and `profiler:export` commands have been removed. * All the profiler storages different than `FileProfilerStorage` have been removed. The removed classes are: From cd66a452c6576fd308716f1c20905c08d20903f2 Mon Sep 17 00:00:00 2001 From: bradbyu Date: Fri, 13 May 2016 10:45:14 -0400 Subject: [PATCH 11/17] Update UPGRADE FROM 2.x to 3.0 --- UPGRADE-3.0.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 475fcbbc80..467c13e644 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -132,7 +132,10 @@ UPGRADE FROM 2.x to 3.0 ### Form - * The `ChoiceToBooleanArrayTransformer`, `ChoicesToBooleanArrayTransformer`, + * The `max_length` option was removed. Use the `attr` option instead by setting it to + an `array` with a `maxlength` key. + + * The `ChoiceToBooleanArrayTransformer`, `ChoicesToBooleanArrayTransformer`, `FixRadioInputListener`, and `FixCheckboxInputListener` classes were removed. * The `choice_list` option of `ChoiceType` was removed. From 94e4706609b5bfe5f0ac2c26f53141042a65b55c Mon Sep 17 00:00:00 2001 From: Peter Rehm Date: Thu, 19 May 2016 16:20:34 +0200 Subject: [PATCH 12/17] Fixed server status command when port has been omitted --- .../Bundle/FrameworkBundle/Command/ServerStatusCommand.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php index 2c6d2c49ff..fa5c537a0c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php @@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** @@ -31,6 +32,7 @@ class ServerStatusCommand extends ServerCommand $this ->setDefinition(array( new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'), + new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'), )) ->setName('server:status') ->setDescription('Outputs the status of the built-in web server for the given address') @@ -44,6 +46,10 @@ class ServerStatusCommand extends ServerCommand { $address = $input->getArgument('address'); + if (false === strpos($address, ':')) { + $address = $address.':'.$input->getOption('port'); + } + // remove an orphaned lock file if (file_exists($this->getLockFile($address)) && !$this->isServerRunning($address)) { unlink($this->getLockFile($address)); From a4b1fa669432ff433df65a7e89e122c3d7d8b892 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 14 May 2016 17:57:37 +0200 Subject: [PATCH 13/17] chomp newlines only at the end of YAML documents --- src/Symfony/Component/Yaml/Parser.php | 26 ++++++++++++++----- .../Component/Yaml/Tests/ParserTest.php | 3 ++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index a37e3e6948..67f780aaae 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -25,6 +25,7 @@ class Parser const FOLDED_SCALAR_PATTERN = self::BLOCK_SCALAR_HEADER_PATTERN; private $offset = 0; + private $totalNumberOfLines; private $lines = array(); private $currentLineNb = -1; private $currentLine = ''; @@ -33,11 +34,13 @@ class Parser /** * Constructor. * - * @param int $offset The offset of YAML document (used for line numbers in error messages) + * @param int $offset The offset of YAML document (used for line numbers in error messages) + * @param int|null $totalNumberOfLines The overall number of lines being parsed */ - public function __construct($offset = 0) + public function __construct($offset = 0, $totalNumberOfLines = null) { $this->offset = $offset; + $this->totalNumberOfLines = $totalNumberOfLines; } /** @@ -61,6 +64,10 @@ class Parser $value = $this->cleanup($value); $this->lines = explode("\n", $value); + if (null === $this->totalNumberOfLines) { + $this->totalNumberOfLines = count($this->lines); + } + if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { $mbEncoding = mb_internal_encoding(); mb_internal_encoding('UTF-8'); @@ -93,7 +100,7 @@ class Parser // array if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) { $c = $this->getRealCurrentLineNb() + 1; - $parser = new self($c); + $parser = new self($c, $this->totalNumberOfLines); $parser->refs = &$this->refs; $data[] = $parser->parse($this->getNextEmbedBlock(null, true), $exceptionOnInvalidType, $objectSupport); } else { @@ -102,7 +109,7 @@ class Parser ) { // this is a compact notation element, add to next block and parse $c = $this->getRealCurrentLineNb(); - $parser = new self($c); + $parser = new self($c, $this->totalNumberOfLines); $parser->refs = &$this->refs; $block = $values['value']; @@ -153,7 +160,7 @@ class Parser $value = $this->getNextEmbedBlock(); } $c = $this->getRealCurrentLineNb() + 1; - $parser = new self($c); + $parser = new self($c, $this->totalNumberOfLines); $parser->refs = &$this->refs; $parsed = $parser->parse($value, $exceptionOnInvalidType, $objectSupport); @@ -190,7 +197,7 @@ class Parser $data[$key] = null; } else { $c = $this->getRealCurrentLineNb() + 1; - $parser = new self($c); + $parser = new self($c, $this->totalNumberOfLines); $parser->refs = &$this->refs; $data[$key] = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport); } @@ -528,6 +535,8 @@ class Parser if ($notEOF) { $blockLines[] = ''; $this->moveToPreviousLine(); + } elseif (!$notEOF && !$this->isCurrentLineLastLineInDocument()) { + $blockLines[] = ''; } // folded style @@ -634,6 +643,11 @@ class Parser return '' !== $ltrimmedLine && $ltrimmedLine[0] === '#'; } + private function isCurrentLineLastLineInDocument() + { + return ($this->offset + $this->currentLineNb) >= ($this->totalNumberOfLines - 1); + } + /** * Cleanups a YAML string to be parsed. * diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 34cc81b2d3..6645c36108 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -826,6 +826,7 @@ EOT foo # bar baz + EOT , ), @@ -854,7 +855,7 @@ EOT; $expected = array( 'foo' => array( 'bar' => array( - 'scalar-block' => 'line1 line2>', + 'scalar-block' => "line1 line2>\n", ), 'baz' => array( 'foobar' => null, From c2f7fedfd6494ac8e97347e554b0d3d16f7086eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sun, 22 May 2016 13:47:44 +0200 Subject: [PATCH 14/17] [Serializer] Add test for ignored attributes during denormalization --- .../Tests/Normalizer/ObjectNormalizerTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index c0602d7fa6..398a579b9f 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -324,6 +324,19 @@ class ObjectNormalizerTest extends \PHPUnit_Framework_TestCase ); } + public function testIgnoredAttributesDenormalize() + { + $this->normalizer->setIgnoredAttributes(array('fooBar', 'bar', 'baz')); + + $obj = new ObjectDummy(); + $obj->setFoo('foo'); + + $this->assertEquals( + $obj, + $this->normalizer->denormalize(array('fooBar' => 'fooBar', 'foo' => 'foo', 'baz' => 'baz'), __NAMESPACE__.'\ObjectDummy') + ); + } + public function provideCallbacks() { return array( From 717e1a9e47d0899efcb65676cf10285a43a03a23 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 22 May 2016 18:02:36 +0200 Subject: [PATCH 15/17] [Yaml] properly handle unindented collections --- src/Symfony/Component/Yaml/Parser.php | 2 +- .../Component/Yaml/Tests/ParserTest.php | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index a37e3e6948..d27968bb40 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -711,7 +711,7 @@ class Parser */ private function isStringUnIndentedCollectionItem() { - return 0 === strpos($this->currentLine, '- '); + return '-' === rtrim($this->currentLine) || 0 === strpos($this->currentLine, '- '); } /** diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 34cc81b2d3..ba4064272a 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -557,6 +557,34 @@ EOF ); } + public function testSequenceInMappingStartedBySingleDashLine() + { + $yaml = << array( + array( + 'b' => array( + array( + 'bar' => 'baz', + ), + ), + ), + 'foo', + ), + 'd' => 'e', + ); + + $this->assertSame($expected, $this->parser->parse($yaml)); + } + /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ From 02070f9fd353df6395db1cff0a46eb0ea3cbb605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Mor=C3=A1vek=20=28moravek=2Emartin=29?= Date: Sun, 22 May 2016 21:49:29 +0900 Subject: [PATCH 16/17] People - person singularization --- src/Symfony/Component/PropertyAccess/StringUtil.php | 3 +++ src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/Symfony/Component/PropertyAccess/StringUtil.php b/src/Symfony/Component/PropertyAccess/StringUtil.php index 248a6483d8..caa8c3d7e1 100644 --- a/src/Symfony/Component/PropertyAccess/StringUtil.php +++ b/src/Symfony/Component/PropertyAccess/StringUtil.php @@ -124,6 +124,9 @@ class StringUtil // chateaux (chateau) array('xuae', 4, false, true, 'eau'), + + // people (person) + array('elpoep', 6, true, true, 'person'), ); /** diff --git a/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php b/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php index 0fd6bb69b2..983e355cb9 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php @@ -107,6 +107,8 @@ class StringUtilTest extends \PHPUnit_Framework_TestCase array('objectives', 'objective'), array('oxen', 'ox'), array('parties', 'party'), + array('people', 'person'), + array('persons', 'person'), array('phenomena', array('phenomenon', 'phenomenum')), array('photos', 'photo'), array('pianos', 'piano'), From 9bdaba48018b459bb8fdc3673e6155e0e418adb7 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 23 May 2016 11:57:38 +0200 Subject: [PATCH 17/17] [Yaml] fix exception contexts --- src/Symfony/Component/Yaml/Parser.php | 8 ++++---- src/Symfony/Component/Yaml/Tests/ParserTest.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 46e7549749..2739723c7e 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -88,7 +88,7 @@ class Parser $isRef = $isInPlace = $isProcessed = false; if (preg_match('#^\-((?P\s+)(?P.+?))?\s*$#u', $this->currentLine, $values)) { if ($context && 'mapping' == $context) { - throw new ParseException('You cannot define a sequence item when in a mapping'); + throw new ParseException('You cannot define a sequence item when in a mapping', $this->getRealCurrentLineNb() + 1, $this->currentLine); } $context = 'sequence'; @@ -127,7 +127,7 @@ class Parser } } 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('"', "'")))) { if ($context && 'sequence' == $context) { - throw new ParseException('You cannot define a mapping item when in a sequence'); + throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine); } $context = 'mapping'; @@ -214,7 +214,7 @@ class Parser } else { // multiple documents are not supported if ('---' === $this->currentLine) { - throw new ParseException('Multiple documents are not supported.'); + throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine); } // 1-liner optionally followed by newline(s) @@ -449,7 +449,7 @@ class Parser } if (!array_key_exists($value, $this->refs)) { - throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLine); + throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine); } return $this->refs[$value]; diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index c3fc6b2ada..87f0cdbb1b 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -525,7 +525,7 @@ EOF; /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException - * @expectedExceptionMessage Multiple documents are not supported. + * @expectedExceptionMessageRegExp /^Multiple documents are not supported.+/ */ public function testMultipleDocumentsNotSupportedException() {