diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 8925b91189..8c509b36f0 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -398,8 +398,11 @@ UPGRADE FROM 2.x to 3.0 ``` - * The `ChoiceToBooleanArrayTransformer`, `ChoicesToBooleanArrayTransformer`, - `FixRadioInputListener`, and `FixCheckboxInputListener` classes were removed. + * 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. @@ -636,6 +639,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. @@ -1737,8 +1745,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: diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php index b6ec558701..d7cb9e7d08 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; use Symfony\Component\Console\Style\SymfonyStyle; @@ -32,6 +33,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') @@ -46,6 +48,10 @@ class ServerStatusCommand extends ServerCommand $io = new SymfonyStyle($input, $output); $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)); 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'), ); 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 c9103ae419..bd8213721e 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 @@ -82,6 +82,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) { @@ -255,8 +269,7 @@ stackElement.loading = false; stackElement.error = self.status < 200 || self.status >= 400; stackElement.statusCode = self.status; - stackElement.profile = self.getResponseHeader("X-Debug-Token"); - stackElement.profilerUrl = self.getResponseHeader("X-Debug-Token-Link"); + extractHeaders(self, stackElement); Sfjs.renderAjaxRequests(); } 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)); diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index 5fdcd5cdb4..f4932fc82c 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -580,6 +580,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/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 8e1b06e0ff..fdf0edcfb4 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -45,8 +45,8 @@ class AutowirePass implements CompilerPassInterface $this->completeDefinition($id, $definition); } } - } catch (\Error $e) { } catch (\Exception $e) { + } catch (\Throwable $e) { } spl_autoload_unregister($throwingAutoloader); @@ -283,7 +283,7 @@ class AutowirePass implements CompilerPassInterface try { $this->completeDefinition($argumentId, $argumentDefinition); - } catch (\RuntimeException $e) { + } catch (RuntimeException $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); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 57b0f086c0..ce0336b3e4 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -542,6 +542,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); } @@ -723,6 +727,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' diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index b04d09bf1f..5d91a9fd1e 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -312,6 +312,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( diff --git a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php index 681b7bdbee..af956ee06b 100644 --- a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php @@ -34,7 +34,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 28206025d5..8fb2024dd5 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 */ diff --git a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php index da6e51d6b4..ee70b9d0c7 100644 --- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php @@ -128,6 +128,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); diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index c45ba46b87..de1101f009 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -24,6 +24,7 @@ class Parser const BLOCK_SCALAR_HEADER_PATTERN = '(?P\||>)(?P\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P +#.*)?'; private $offset = 0; + private $totalNumberOfLines; private $lines = array(); private $currentLineNb = -1; private $currentLine = ''; @@ -32,11 +33,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; } /** @@ -85,6 +88,10 @@ class Parser $value = $this->cleanup($value); $this->lines = explode("\n", $value); + if (null === $this->totalNumberOfLines) { + $this->totalNumberOfLines = count($this->lines); + } + if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) { $mbEncoding = mb_internal_encoding(); mb_internal_encoding('UTF-8'); @@ -106,7 +113,7 @@ class Parser $isRef = $mergeNode = 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'; @@ -118,7 +125,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), $flags); } else { @@ -127,7 +134,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']; @@ -145,7 +152,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'; @@ -192,7 +199,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, $flags); @@ -243,7 +250,7 @@ class Parser } } else { $c = $this->getRealCurrentLineNb() + 1; - $parser = new self($c); + $parser = new self($c, $this->totalNumberOfLines); $parser->refs = &$this->refs; $value = $parser->parse($this->getNextEmbedBlock(), $flags); // Spec: Keys MUST be unique; first one wins. @@ -266,7 +273,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) @@ -511,7 +518,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]; @@ -609,6 +616,8 @@ class Parser if ($notEOF) { $blockLines[] = ''; $this->moveToPreviousLine(); + } elseif (!$notEOF && !$this->isCurrentLineLastLineInDocument()) { + $blockLines[] = ''; } // folded style @@ -715,6 +724,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. * @@ -792,7 +806,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 bddf969744..4ebee0fd89 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -633,7 +633,7 @@ EOF; /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException - * @expectedExceptionMessage Multiple documents are not supported. + * @expectedExceptionMessageRegExp /^Multiple documents are not supported.+/ */ public function testMultipleDocumentsNotSupportedException() { @@ -665,6 +665,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 */ @@ -1014,6 +1042,7 @@ EOT foo # bar baz + EOT , ), @@ -1042,7 +1071,7 @@ EOT; $expected = array( 'foo' => array( 'bar' => array( - 'scalar-block' => 'line1 line2>', + 'scalar-block' => "line1 line2>\n", ), 'baz' => array( 'foobar' => null,