From 6161438f57458d78b494b4cde3542a550d6232d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Haso=C5=88?= Date: Thu, 25 Feb 2016 23:33:26 +0100 Subject: [PATCH 01/83] [DependencyInjection] Enabled alias for service_container --- .../Compiler/ReplaceAliasByActualDefinitionPass.php | 4 ++++ .../Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php index fef070bcff07e..6a6b214bb374d 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php @@ -42,6 +42,10 @@ public function process(ContainerBuilder $container) foreach ($container->getAliases() as $id => $alias) { $aliasId = (string) $alias; + if ('service_container' === $aliasId) { + continue; + } + try { $definition = $container->getDefinition($aliasId); } catch (InvalidArgumentException $e) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php index ac1609f5d7d58..c4470dd402160 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php @@ -32,6 +32,8 @@ public function testProcess() $container->setAlias('a_alias', 'a'); $container->setAlias('b_alias', 'b'); + $container->setAlias('container', 'service_container'); + $this->process($container); $this->assertTrue($container->has('a'), '->process() does nothing to public definitions.'); @@ -42,6 +44,7 @@ public function testProcess() '->process() replaces alias to actual.' ); $this->assertSame('b_alias', $aDefinition->getFactoryService()); + $this->assertTrue($container->has('container')); } /** From b3da6a11a729e690fd924b35ce731e647301960c Mon Sep 17 00:00:00 2001 From: Arjen van der Meijden Date: Sat, 19 Mar 2016 09:30:33 +0100 Subject: [PATCH 02/83] [Routing] Don't needlessly execute strtr's as they are fairly expensive --- .../Routing/Generator/UrlGenerator.php | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 6931bad09d598..978280f776413 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -75,6 +75,11 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt '%7C' => '|', ); + /** + * @var string This regexp matches all characters that are not or should not be encoded by rawurlencode (see list in array above). + */ + private $urlEncodingSkipRegexp = '#[^-.~a-zA-Z0-9_/@:;,=+!*|]#'; + /** * Constructor. * @@ -182,19 +187,21 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa if ('' === $url) { $url = '/'; + } else if (preg_match($this->urlEncodingSkipRegexp, $url)) { + // the contexts base URL is already encoded (see Symfony\Component\HttpFoundation\Request) + $url = strtr(rawurlencode($url), $this->decodedChars); } - // the contexts base URL is already encoded (see Symfony\Component\HttpFoundation\Request) - $url = strtr(rawurlencode($url), $this->decodedChars); - // the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3 // so we need to encode them as they are not used for this purpose here // otherwise we would generate a URI that, when followed by a user agent (e.g. browser), does not match this route - $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/')); - if ('/..' === substr($url, -3)) { - $url = substr($url, 0, -2).'%2E%2E'; - } elseif ('/.' === substr($url, -2)) { - $url = substr($url, 0, -1).'%2E'; + if(false !== strpos($url, '/.')) { + $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/')); + if ('/..' === substr($url, -3)) { + $url = substr($url, 0, -2).'%2E%2E'; + } elseif ('/.' === substr($url, -2)) { + $url = substr($url, 0, -1).'%2E'; + } } $schemeAuthority = ''; @@ -268,7 +275,7 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa if ($extra && $query = http_build_query($extra, '', '&')) { // "/" and "?" can be left decoded for better user experience, see // http://tools.ietf.org/html/rfc3986#section-3.4 - $url .= '?'.strtr($query, array('%2F' => '/')); + $url .= '?'.(false === strpos($query, '%2F') ? $query : strtr($query, array('%2F' => '/'))); } return $url; From 1ef2edf4b48589084ef8589eda022d648337e12d Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Wed, 23 Mar 2016 18:41:29 +0100 Subject: [PATCH 03/83] [Routing] add query param if value is different from default --- .../Routing/Generator/UrlGenerator.php | 5 ++++- .../Tests/Generator/UrlGeneratorTest.php | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index dc46c60fb98c7..68f62a064c386 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -257,7 +257,10 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa } // add a query string if needed - $extra = array_diff_key($parameters, $variables, $defaults); + $extra = array_udiff_assoc(array_diff_key($parameters, $variables), $defaults, function ($a, $b) { + return $a == $b ? 0 : 1; + }); + if ($extra && $query = http_build_query($extra, '', '&')) { $url .= '?'.$query; } diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index d7b74f01e1bb3..056506b6c85cf 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -291,10 +291,22 @@ public function testNullForOptionalParameterIsIgnored() public function testQueryParamSameAsDefault() { - $routes = $this->getRoutes('test', new Route('/test', array('default' => 'value'))); + $routes = $this->getRoutes('test', new Route('/test', array('page' => 1))); - $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => 'foo'))); - $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => 'value'))); + $this->assertSame('/app.php/test?page=2', $this->getGenerator($routes)->generate('test', array('page' => 2))); + $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => 1))); + $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => '1'))); + $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test')); + } + + public function testArrayQueryParamSameAsDefault() + { + $routes = $this->getRoutes('test', new Route('/test', array('array' => array('foo', 'bar')))); + + $this->assertSame('/app.php/test?array%5B0%5D=bar&array%5B1%5D=foo', $this->getGenerator($routes)->generate('test', array('array' => array('bar', 'foo')))); + $this->assertSame('/app.php/test?array%5Ba%5D=foo&array%5Bb%5D=bar', $this->getGenerator($routes)->generate('test', array('array' => array('a' => 'foo', 'b' => 'bar')))); + $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array('foo', 'bar')))); + $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array(1 => 'bar', 0 => 'foo')))); $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test')); } From ae9bae7e16fd27e17339f2dbc45bcafc2294949d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 24 Mar 2016 23:24:57 +0100 Subject: [PATCH 04/83] [phpunit] disable prophecy --- phpunit | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit b/phpunit index d2da42616d4eb..6d66f7b2b252a 100755 --- a/phpunit +++ b/phpunit @@ -51,6 +51,7 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ $zip->extractTo(getcwd()); $zip->close(); chdir("phpunit-$PHPUNIT_VERSION"); + passthru("$COMPOSER remove --no-update phpspec/prophecy"); passthru("$COMPOSER remove --no-update symfony/yaml"); passthru("$COMPOSER require --dev --no-update symfony/phpunit-bridge \">=3.1@dev\""); passthru("$COMPOSER install --prefer-dist --no-progress --ansi", $exit); From 562f5e4394cdefa9a9a6de2b86119174e5c5cd50 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sat, 26 Mar 2016 02:34:58 +0100 Subject: [PATCH 05/83] [Form] remove useless code in ChoiceType `ChoiceListFactoryInterface` expected `$group_by` to be a callable or null not an array. The factory defaults `group_by` to `ChoiceListInterface::getStructuredValues`. --- .../Form/Extension/Core/Type/ChoiceType.php | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index 835f3767e54d9..26af37b9ace79 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -420,7 +420,7 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('choice_value', array('null', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath')); $resolver->setAllowedTypes('choice_attr', array('null', 'array', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath')); $resolver->setAllowedTypes('preferred_choices', array('array', '\Traversable', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath')); - $resolver->setAllowedTypes('group_by', array('null', 'array', '\Traversable', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath')); + $resolver->setAllowedTypes('group_by', array('null', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath')); } /** @@ -431,21 +431,6 @@ public function getName() return 'choice'; } - private static function flipRecursive($choices, &$output = array()) - { - foreach ($choices as $key => $value) { - if (is_array($value)) { - $output[$key] = array(); - self::flipRecursive($value, $output[$key]); - continue; - } - - $output[$value] = $key; - } - - return $output; - } - /** * Adds the sub fields for an expanded choice field. * @@ -503,14 +488,6 @@ private function addSubForm(FormBuilderInterface $builder, $name, ChoiceView $ch private function createChoiceListView(ChoiceListInterface $choiceList, array $options) { - // If no explicit grouping information is given, use the structural - // information from the "choices" option for creating groups - if (!$options['group_by'] && $options['choices']) { - $options['group_by'] = !$options['choices_as_values'] - ? self::flipRecursive($options['choices']) - : $options['choices']; - } - return $this->choiceListFactory->createView( $choiceList, $options['preferred_choices'], From bc2182883825061879a6dd35e9eae5951255d4be Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sun, 27 Mar 2016 13:58:34 +0200 Subject: [PATCH 06/83] [Form] cs fixes in date types --- .../Component/Form/Extension/Core/Type/DateTimeType.php | 2 +- src/Symfony/Component/Form/Extension/Core/Type/DateType.php | 6 +++--- src/Symfony/Component/Form/Extension/Core/Type/TimeType.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php index 5a653233b97e0..dc3a988fb4409 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php @@ -198,7 +198,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) public function setDefaultOptions(OptionsResolverInterface $resolver) { $compound = function (Options $options) { - return $options['widget'] !== 'single_text'; + return 'single_text' !== $options['widget']; }; // Defaults to the value of "widget" diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php index 4d5935c048ff0..febf86c83fc07 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php @@ -78,7 +78,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) $pattern ); - // new \intlDateFormatter may return null instead of false in case of failure, see https://bugs.php.net/bug.php?id=66323 + // new \IntlDateFormatter may return null instead of false in case of failure, see https://bugs.php.net/bug.php?id=66323 if (!$formatter) { throw new InvalidOptionsException(intl_get_error_message(), intl_get_error_code()); } @@ -171,7 +171,7 @@ public function finishView(FormView $view, FormInterface $form, array $options) public function setDefaultOptions(OptionsResolverInterface $resolver) { $compound = function (Options $options) { - return $options['widget'] !== 'single_text'; + return 'single_text' !== $options['widget']; }; $emptyValue = $emptyValueDefault = function (Options $options) { @@ -196,7 +196,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) }; $format = function (Options $options) { - return $options['widget'] === 'single_text' ? DateType::HTML5_FORMAT : DateType::DEFAULT_FORMAT; + return 'single_text' === $options['widget'] ? DateType::HTML5_FORMAT : DateType::DEFAULT_FORMAT; }; $resolver->setDefaults(array( diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php index fc6362c24ca39..e6eca1059e6b4 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php @@ -157,7 +157,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) public function setDefaultOptions(OptionsResolverInterface $resolver) { $compound = function (Options $options) { - return $options['widget'] !== 'single_text'; + return 'single_text' !== $options['widget']; }; $emptyValue = $emptyValueDefault = function (Options $options) { From 047674ab8f495c9f27a19316f26dd91dd1a0ebd1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 27 Mar 2016 15:23:48 +0200 Subject: [PATCH 07/83] updated CHANGELOG for 2.8.4 --- CHANGELOG-2.8.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index 38abdc97b27f1..7b0fb6cfb3131 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,62 @@ in 2.8 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.8.0...v2.8.1 +* 2.8.4 (2016-03-27) + + * bug #18298 [Validator] do not treat payload as callback (xabbuh) + * bug #18275 [Form] Fix BC break introduced in #14403 (HeahDude) + * bug #18271 [FileSystem] Google app engine filesystem (swordbeta) + * bug #18255 [HttpFoundation] Fix support of custom mime types with parameters (Ener-Getick) + * bug #18272 [Bridge\PhpUnit] Workaround old phpunit bug, no colors in weak mode, add tests (nicolas-grekas) + * bug #18259 [PropertyAccess] Backport fixes from 2.7 (nicolas-grekas) + * bug #18261 [PropertyAccess] Fix isPropertyWritable not using the reflection cache (nicolas-grekas) + * bug #18224 [PropertyAccess] Remove most ref mismatches to improve perf (nicolas-grekas) + * bug #18237 [WebProfilerBundle] Added table-layout property to AJAX toolbar css (kevintweber) + * bug #18209 [PropertyInfo] Support Doctrine custom mapping type in DoctrineExtractor (teohhanhui) + * bug #18210 [PropertyAccess] Throw an UnexpectedTypeException when the type do not match (dunglas, nicolas-grekas) + * bug #18216 [Intl] Fix invalid numeric literal on PHP 7 (nicolas-grekas) + * bug #18147 [Validator] EmailValidator cannot extract hostname if email contains multiple @ symbols (natechicago) + * bug #18023 [Process] getIncrementalOutput should work without calling getOutput (romainneutron) + * bug #18175 [Translation] Add support for fuzzy tags in PoFileLoader (nud) + * bug #18179 [Form] Fix NumberToLocalizedStringTransformer::reverseTransform with big integers (ovrflo, nicolas-grekas) + * bug #18164 [HttpKernel] set s-maxage only if all responses are cacheable (xabbuh) + * bug #18150 [Process] Wait a bit less on Windows (nicolas-grekas) + * bug #18130 [Debug] Replaced logic for detecting filesystem case sensitivity (Dan Blows) + * bug #18137 Autowiring the concrete class too - consistent with behavior of other services (weaverryan) + * bug #18087 [WebProfiler] Sidebar button padding (rvanlaak) + * bug #18080 [HttpFoundation] Set the Content-Range header if the requested Range is unsatisfied (jakzal) + * bug #18084 [HttpFoundation] Avoid warnings when checking malicious IPs (jakzal) + * bug #18066 [Process] Fix pipes handling (nicolas-grekas) + * bug #18078 [Console] Fix an autocompletion question helper issue with non-sequentially indexed choices (jakzal) + * bug #18048 [HttpKernel] Fix mem usage when stripping the prod container (nicolas-grekas) + * bug #18065 [Finder] Partially revert #17134 to fix a regression (jakzal) + * bug #18018 [HttpFoundation] exception when registering bags for started sessions (xabbuh) + * bug #18054 [Filesystem] Fix false positive in ->remove() (nicolas-grekas) + * bug #18049 [Validator] Fix the locale validator so it treats a locale alias as a valid locale (jakzal) + * bug #18019 [Intl] Update ICU to version 55 (jakzal) + * bug #18015 [Process] Fix memory issue when using large input streams (romainneutron) + * bug #16656 [HttpFoundation] automatically generate safe fallback filename (xabbuh) + * bug #15794 [Console] default to stderr in the console helpers (alcohol) + * bug #17984 Allow to normalize \Traversable when serializing xml (Ener-Getick) + * bug #17434 Improved the error message when a template is not found (rvanginneken, javiereguiluz) + * bug #17687 Improved the error message when using "@" in a decorated service (javiereguiluz) + * bug #17744 Improve error reporting in router panel of web profiler (javiereguiluz) + * bug #17894 [FrameworkBundle] Fix a regression in handling absolute template paths (jakzal) + * bug #17990 [DoctrineBridge][Form] Fix performance regression in EntityType (kimlai) + * bug #17595 [HttpKernel] Remove _path from query parameters when fragment is a subrequest (cmenning) + * bug #17986 [DomCrawler] Dont use LIBXML_PARSEHUGE by default (nicolas-grekas) + * bug #17668 add 'guid' to list of exception to filter out (garak) + * bug #17615 Ensure backend slashes for symlinks on Windows systems (cpsitgmbh) + * bug #17626 Try to delete broken symlinks (IchHabRecht) + * bug #17978 [Yaml] ensure dump indentation to be greather than zero (xabbuh) + * bug #16886 [Form] [ChoiceType] Prefer placeholder to empty_value (boite) + * bug #17976 [WebProfilerBundle] fix debug toolbar rendering by removing inadvertently added links (craue) + * bug #17971 Variadic controller params (NiR-, fabpot) + * bug #17876 [DependencyInjection] Fixing autowiring bug when some args are set (weaverryan) + * bug #17568 Improved Bootstrap form theme for hidden fields (javiereguiluz) + * bug #17561 [WebProfilerBundle] Fix design issue in profiler when having errors in forms (Pierstoval) + * bug #17925 [Bridge] The WebProcessor now forwards the client IP (magnetik) + * 2.8.3 (2016-02-28) * bug #17947 Fix - #17676 (backport #17919 to 2.3) (Ocramius) From f5c0298b0bb281a53d62f6fba5f934232a85bf7f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 27 Mar 2016 15:23:50 +0200 Subject: [PATCH 08/83] updated VERSION for 2.8.4 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 40e32e50b5e7f..792f0e55ada08 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.4-DEV'; + const VERSION = '2.8.4'; const VERSION_ID = 20804; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 4; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From df01f06a8539272266f0d6437e49c1272dfd81b2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 27 Mar 2016 16:32:56 +0200 Subject: [PATCH 09/83] bumped Symfony version to 2.8.5 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 792f0e55ada08..a804d4bbaf409 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.4'; - const VERSION_ID = 20804; + const VERSION = '2.8.5-DEV'; + const VERSION_ID = 20805; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; - const RELEASE_VERSION = 4; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 5; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From 106ed0660c7dc6053bd9b2b9072ca706640a5d78 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 25 Mar 2016 16:27:11 +0100 Subject: [PATCH 10/83] [ClassLoader] Fix storing not-found classes in APC cache --- src/Symfony/Component/ClassLoader/ApcClassLoader.php | 6 ++++-- .../Component/ClassLoader/ApcUniversalClassLoader.php | 6 ++++-- src/Symfony/Component/ClassLoader/DebugClassLoader.php | 2 +- src/Symfony/Component/ClassLoader/WinCacheClassLoader.php | 6 ++++-- src/Symfony/Component/ClassLoader/XcacheClassLoader.php | 2 +- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/ClassLoader/ApcClassLoader.php b/src/Symfony/Component/ClassLoader/ApcClassLoader.php index 4f71ea173d50b..c21c64e38bfd2 100644 --- a/src/Symfony/Component/ClassLoader/ApcClassLoader.php +++ b/src/Symfony/Component/ClassLoader/ApcClassLoader.php @@ -122,8 +122,10 @@ public function loadClass($class) */ public function findFile($class) { - if (false === $file = apcu_fetch($this->prefix.$class)) { - apcu_store($this->prefix.$class, $file = $this->decorated->findFile($class)); + $file = apcu_fetch($this->prefix.$class, $success); + + if (!$success) { + apcu_store($this->prefix.$class, $file = $this->decorated->findFile($class) ?: null); } return $file; diff --git a/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php b/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php index bedb30f8955ee..bad90267ff991 100644 --- a/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php +++ b/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php @@ -87,8 +87,10 @@ public function __construct($prefix) */ public function findFile($class) { - if (false === $file = apcu_fetch($this->prefix.$class)) { - apcu_store($this->prefix.$class, $file = parent::findFile($class)); + $file = apcu_fetch($this->prefix.$class, $success); + + if (!$success) { + apcu_store($this->prefix.$class, $file = parent::findFile($class) ?: null); } return $file; diff --git a/src/Symfony/Component/ClassLoader/DebugClassLoader.php b/src/Symfony/Component/ClassLoader/DebugClassLoader.php index eec68b2c98617..53be5b5c87bdb 100644 --- a/src/Symfony/Component/ClassLoader/DebugClassLoader.php +++ b/src/Symfony/Component/ClassLoader/DebugClassLoader.php @@ -74,7 +74,7 @@ public function unregister() */ public function findFile($class) { - return $this->classFinder->findFile($class); + return $this->classFinder->findFile($class) ?: null; } /** diff --git a/src/Symfony/Component/ClassLoader/WinCacheClassLoader.php b/src/Symfony/Component/ClassLoader/WinCacheClassLoader.php index 0fc11d019f862..8c846e3c266f8 100644 --- a/src/Symfony/Component/ClassLoader/WinCacheClassLoader.php +++ b/src/Symfony/Component/ClassLoader/WinCacheClassLoader.php @@ -123,8 +123,10 @@ public function loadClass($class) */ public function findFile($class) { - if (false === $file = wincache_ucache_get($this->prefix.$class)) { - wincache_ucache_set($this->prefix.$class, $file = $this->decorated->findFile($class), 0); + $file = wincache_ucache_get($this->prefix.$class, $success); + + if (!$success) { + wincache_ucache_set($this->prefix.$class, $file = $this->decorated->findFile($class) ?: null, 0); } return $file; diff --git a/src/Symfony/Component/ClassLoader/XcacheClassLoader.php b/src/Symfony/Component/ClassLoader/XcacheClassLoader.php index bf512273ef5fe..11da39d6f3ec4 100644 --- a/src/Symfony/Component/ClassLoader/XcacheClassLoader.php +++ b/src/Symfony/Component/ClassLoader/XcacheClassLoader.php @@ -126,7 +126,7 @@ public function findFile($class) if (xcache_isset($this->prefix.$class)) { $file = xcache_get($this->prefix.$class); } else { - $file = $this->decorated->findFile($class); + $file = $this->decorated->findFile($class) ?: null; xcache_set($this->prefix.$class, $file); } From 0d31c3e9cb63ec41ccd0ee90e688e52e29233405 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Mon, 28 Mar 2016 23:46:00 -0500 Subject: [PATCH 11/83] [WebProfilerBundle] Add missing use statement. Request is needed in RouterController::getTraces to be able to create a request. --- .../Bundle/WebProfilerBundle/Controller/RouterController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php index 2be420ba8b0b0..d77eb279f4a69 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\WebProfilerBundle\Controller; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Matcher\UrlMatcherInterface; use Symfony\Component\Routing\Matcher\TraceableUrlMatcher; From d5e8f6f20af3fbef2c620978b082064dcccd5cef Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 29 Mar 2016 16:17:20 +0200 Subject: [PATCH 12/83] [Process] remove dead code --- .../Component/Process/Tests/ProcessTest.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index c33e0837b9a9a..ebe6c2057cc0c 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -901,23 +901,6 @@ public function pipesCodeProvider() return $codes; } - /** - * provides default method names for simple getter/setter. - */ - public function methodProvider() - { - $defaults = array( - array('CommandLine'), - array('Timeout'), - array('WorkingDirectory'), - array('Env'), - array('Stdin'), - array('Options'), - ); - - return $defaults; - } - /** * @param string $commandline * @param null $cwd From ddc8d4ede2be44d2eac5085df5d00b345a2a23e4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 29 Mar 2016 17:56:26 +0200 Subject: [PATCH 13/83] Fixed the styles of the Symfony icon in the web debug toolbar --- .../Bundle/WebProfilerBundle/Resources/views/Icon/symfony.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/symfony.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/symfony.svg index 170e4c0cf941b..30b1c2e9aad51 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/symfony.svg +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/symfony.svg @@ -1,4 +1,4 @@ - + setDeprecated(true); + $builder = new ContainerBuilder(); $builder->createService($definition, 'deprecated_foo'); restore_error_handler(); - $this->assertTrue($wasTriggered); + $this->assertCount(1, $deprecations); + $this->assertContains('The "deprecated_foo" service is deprecated. You should stop using it, as it will soon be removed.', $deprecations[0]); } public function testRegister() diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index d41c583ed53fc..8fea5e8e84438 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -889,9 +889,13 @@ public function testColonInMappingValueException() $deprecations = array(); set_error_handler(function ($type, $msg) use (&$deprecations) { - if (E_USER_DEPRECATED === $type) { - $deprecations[] = $msg; + if (E_USER_DEPRECATED !== $type) { + restore_error_handler(); + + return call_user_func_array('PHPUnit_Util_ErrorHandler::handleError', func_get_args()); } + + $deprecations[] = $msg; }); $this->parser->parse($yaml); From aa4dd4fcf04138da47289f7d5237717527043215 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 29 Mar 2016 21:58:51 +0200 Subject: [PATCH 15/83] fix high deps tests --- .../Twig/Resources/views/Form/form_div_layout.html.twig | 4 ++-- .../Resources/views/Form/widget_attributes.html.php | 3 ++- 2 files changed, 4 insertions(+), 3 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 ae5d7fbed4a4a..4e5b9dd598302 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,10 +314,10 @@ {%- block widget_attributes -%} id="{{ id }}" name="{{ full_name }}" - {%- if read_only and attr.readonly is not defined %} readonly="readonly"{% endif -%} + {%- if read_only %} readonly="readonly"{% endif -%} {%- if disabled %} disabled="disabled"{% endif -%} {%- if required %} required="required"{% endif -%} - {%- for attrname, attrvalue in attr -%} + {%- for attrname, attrvalue in attr if 'readonly' != attrname or not read_only -%} {{- " " -}} {%- if attrname in ['placeholder', 'title'] -%} {{- attrname }}="{{ attrvalue|trans({}, translation_domain) }}" 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 14e65a7991c53..e90298701c682 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,7 +1,8 @@ -id="escape($id) ?>" name="escape($full_name) ?>" readonly="readonly" +id="escape($id) ?>" name="escape($full_name) ?>" readonly="readonly" disabled="disabled" required="required" $v): ?> + escape($k), $view->escape($view['translator']->trans($v, array(), $translation_domain))) ?> From f5ed09c64cb44277443a7619c6bc8870a707666f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 30 Mar 2016 09:21:26 +0200 Subject: [PATCH 16/83] [Form] NumberToLocalizedStringTransformer should return floats when possible --- .../NumberToLocalizedStringTransformer.php | 4 ++++ .../NumberToLocalizedStringTransformerTest.php | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index a18eb957b5ee8..ab11efbf140e4 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -140,6 +140,10 @@ public function reverseTransform($value) throw new TransformationFailedException('I don\'t have a clear idea what infinity looks like'); } + if (is_int($result) && $result === (int) $float = (float) $result) { + $result = $float; + } + if (function_exists('mb_detect_encoding') && false !== $encoding = mb_detect_encoding($value, null, true)) { $length = mb_strlen($value, $encoding); $remainder = mb_substr($value, $position, $length, $encoding); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php index 87cdf964c81ef..4e2c6a18d90e7 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php @@ -434,10 +434,17 @@ public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte() $transformer->reverseTransform("12\xc2\xa0345,678foo"); } - public function testReverseTransformBigint() + public function testReverseTransformBigInt() { $transformer = new NumberToLocalizedStringTransformer(null, true); $this->assertEquals(PHP_INT_MAX - 1, (int) $transformer->reverseTransform((string) (PHP_INT_MAX - 1))); } + + public function testReverseTransformSmallInt() + { + $transformer = new NumberToLocalizedStringTransformer(null, true); + + $this->assertSame(1.0, $transformer->reverseTransform('1')); + } } From b0320967633d5571e211aa80d19e7050a001e096 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 28 Mar 2016 11:08:12 +0200 Subject: [PATCH 17/83] [Debug] Fix handling of php7 throwables --- src/Symfony/Component/Debug/Debug.php | 24 ++++++++++++++++++++ src/Symfony/Component/Debug/ErrorHandler.php | 6 +++++ 2 files changed, 30 insertions(+) diff --git a/src/Symfony/Component/Debug/Debug.php b/src/Symfony/Component/Debug/Debug.php index 82014e4ad42a1..eca19da9e66ec 100644 --- a/src/Symfony/Component/Debug/Debug.php +++ b/src/Symfony/Component/Debug/Debug.php @@ -46,6 +46,30 @@ public static function enable($errorReportingLevel = null, $displayErrors = true ErrorHandler::register($errorReportingLevel, $displayErrors); if ('cli' !== PHP_SAPI) { ExceptionHandler::register(); + + if (PHP_VERSION_ID >= 70000) { + $exceptionHandler = set_exception_handler(function ($throwable) use (&$exceptionHandler) { + if ($throwable instanceof \Exception) { + $exception = $throwable; + } else { + static $refl = null; + + if (null === $refl) { + $refl = array(); + foreach (array('file', 'line', 'trace') as $prop) { + $prop = new \ReflectionProperty('Exception', $prop); + $prop->setAccessible(true); + $refl[] = $prop; + } + } + $exception = new \Exception($throwable->getMessage(), $throwable->getCode()); + foreach ($refl as $prop) { + $prop->setValue($exception, $throwable->{'get'.$prop->name}()); + } + } + $exceptionHandler($exception); + }); + } // CLI - display errors only if they're not already logged to STDERR } elseif ($displayErrors && (!ini_get('log_errors') || ini_get('error_log'))) { ini_set('display_errors', 1); diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index 43e196242a7e1..f12ece7a0d101 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -197,6 +197,12 @@ public function handleFatal() $exceptionHandler = set_exception_handler(function () {}); restore_exception_handler(); + if (PHP_VERSION_ID >= 70000 && $exceptionHandler instanceof \Closure) { + $reflector = new \ReflectionFunction($exceptionHandler); + foreach ($reflector->getStaticVariables() as $exceptionHandler) { + break; + } + } if (is_array($exceptionHandler) && $exceptionHandler[0] instanceof ExceptionHandler) { $level = isset($this->levels[$type]) ? $this->levels[$type] : $type; $message = sprintf('%s: %s in %s line %d', $level, $error['message'], $error['file'], $error['line']); From 73361771459f05a598eb14120a5b860270c98e83 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 29 Mar 2016 19:31:32 +0200 Subject: [PATCH 18/83] [Debug] Fix case sensitivity checks --- .../Component/Debug/DebugClassLoader.php | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php index fc036a628658f..36afa369301b2 100644 --- a/src/Symfony/Component/Debug/DebugClassLoader.php +++ b/src/Symfony/Component/Debug/DebugClassLoader.php @@ -51,15 +51,25 @@ public function __construct($classLoader) } if (!isset(self::$caseCheck)) { - if(!file_exists(strtolower(__FILE__))) { + $file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), DIRECTORY_SEPARATOR); + $i = strrpos($file, DIRECTORY_SEPARATOR); + $dir = substr($file, 0, 1 + $i); + $file = substr($file, 1 + $i); + $test = strtoupper($file) === $file ? strtolower($file) : strtoupper($file); + $test = realpath($dir.$test); + + if (false === $test || false === $i) { // filesystem is case sensitive self::$caseCheck = 0; - } elseif(realpath(strtolower(__FILE__)) === __FILE__) { - // filesystem is not case sensitive + } elseif (substr($test, -strlen($file)) === $file) { + // filesystem is case insensitive and realpath() normalizes the case of characters self::$caseCheck = 1; - } else { - // filesystem is not case sensitive AND realpath() fails to normalize case + } elseif (false !== stripos(PHP_OS, 'darwin')) { + // on MacOSX, HFS+ is case insensitive but realpath() doesn't normalize the case of characters self::$caseCheck = 2; + } else { + // filesystem case checks failed, fallback to disabling them + self::$caseCheck = 0; } } } From 3008228b48d6285dcfbd10422029c0c55a9e713e Mon Sep 17 00:00:00 2001 From: Teoh Han Hui Date: Wed, 30 Mar 2016 17:23:00 +0800 Subject: [PATCH 19/83] [PropertyInfo] Extract nullable and collection key type for Doctrine associations --- .../PropertyInfo/DoctrineExtractor.php | 48 ++++++++++++++++++- .../PropertyInfo/DoctrineExtractorTest.php | 11 ++++- .../PropertyInfo/Fixtures/DoctrineDummy.php | 5 ++ .../Fixtures/DoctrineRelation.php | 6 +++ 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index ecd25088be0f4..6e8c29e16b0dd 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -71,7 +71,9 @@ public function getTypes($class, $property, array $context = array()) if ($metadata->isSingleValuedAssociation($property)) { if ($metadata instanceof ClassMetadataInfo) { - $nullable = isset($metadata->discriminatorColumn['nullable']) ? $metadata->discriminatorColumn['nullable'] : false; + $associationMapping = $metadata->getAssociationMapping($property); + + $nullable = $this->isAssociationNullable($associationMapping); } else { $nullable = false; } @@ -79,12 +81,25 @@ public function getTypes($class, $property, array $context = array()) return array(new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $class)); } + $collectionKeyType = Type::BUILTIN_TYPE_INT; + + if ($metadata instanceof ClassMetadataInfo) { + $associationMapping = $metadata->getAssociationMapping($property); + + if (isset($associationMapping['indexBy'])) { + $indexProperty = $associationMapping['indexBy']; + $typeOfField = $metadata->getTypeOfField($indexProperty); + + $collectionKeyType = $this->getPhpType($typeOfField); + } + } + return array(new Type( Type::BUILTIN_TYPE_OBJECT, false, 'Doctrine\Common\Collections\Collection', true, - new Type(Type::BUILTIN_TYPE_INT), + new Type($collectionKeyType), new Type(Type::BUILTIN_TYPE_OBJECT, false, $class) )); } @@ -118,6 +133,35 @@ public function getTypes($class, $property, array $context = array()) } } + /** + * Determines whether an association is nullable. + * + * @param array $associationMapping + * + * @return bool + * + * @see https://github.com/doctrine/doctrine2/blob/v2.5.4/lib/Doctrine/ORM/Tools/EntityGenerator.php#L1221-L1246 + */ + private function isAssociationNullable(array $associationMapping) + { + if (isset($associationMapping['id']) && $associationMapping['id']) { + return false; + } + + if (!isset($associationMapping['joinColumns'])) { + return true; + } + + $joinColumns = $associationMapping['joinColumns']; + foreach ($joinColumns as $joinColumn) { + if (isset($joinColumn['nullable']) && !$joinColumn['nullable']) { + return false; + } + } + + return true; + } + /** * Gets the corresponding built-in PHP type. * diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php index ca098b6fc8e70..1bc57b1140fae 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php @@ -54,6 +54,7 @@ public function testGetProperties() 'customFoo', 'foo', 'bar', + 'indexedBar', ), $this->extractor->getProperties('Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineDummy') ); @@ -75,7 +76,7 @@ public function typesProvider() array('bool', array(new Type(Type::BUILTIN_TYPE_BOOL))), array('binary', array(new Type(Type::BUILTIN_TYPE_RESOURCE))), array('json', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true))), - array('foo', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation'))), + array('foo', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation'))), array('bar', array(new Type( Type::BUILTIN_TYPE_OBJECT, false, @@ -84,6 +85,14 @@ public function typesProvider() new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation') ))), + array('indexedBar', array(new Type( + Type::BUILTIN_TYPE_OBJECT, + false, + 'Doctrine\Common\Collections\Collection', + true, + new Type(Type::BUILTIN_TYPE_STRING), + new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation') + ))), array('simpleArray', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)))), array('customFoo', null), array('notMapped', null), diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php index 0b6b7bb544039..317d14257b203 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php @@ -40,6 +40,11 @@ class DoctrineDummy */ public $bar; + /** + * @ManyToMany(targetEntity="DoctrineRelation", indexBy="guid") + */ + protected $indexedBar; + /** * @Column(type="guid") */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php index bfb27e9338d99..23f64d829e030 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures; use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\Mapping\Id; /** @@ -26,4 +27,9 @@ class DoctrineRelation * @Column(type="smallint") */ public $id; + + /** + * @Column(type="guid") + */ + protected $guid; } From 8814ed023df4b569e5541a4aed0848f4a868f353 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 30 Mar 2016 11:37:19 +0200 Subject: [PATCH 20/83] [ci] Get ICU/intl from github instead of nebm.ist.utl.pt/~glopes --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 35d4ba0e81e74..8491cd23db2fb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,11 +21,11 @@ install: - IF %PHP%==1 appveyor DownloadFile https://curl.haxx.se/ca/cacert.pem - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-5.3.3-nts-Win32-VC9-x86.zip - IF %PHP%==1 7z x php-5.3.3-nts-Win32-VC9-x86.zip -y >nul - - IF %PHP%==1 appveyor DownloadFile http://nebm.ist.utl.pt/~glopes/misc/intl_win/ICU-51.2-dlls.zip + - IF %PHP%==1 appveyor DownloadFile https://raw.githubusercontent.com/symfony/binary-utils/master/ICU-51.2-dlls.zip - IF %PHP%==1 7z x ICU-51.2-dlls.zip -y >nul - IF %PHP%==1 del /Q *.zip - IF %PHP%==1 cd ext - - IF %PHP%==1 appveyor DownloadFile http://nebm.ist.utl.pt/~glopes/misc/intl_win/php_intl-3.0.0-5.3-nts-vc9-x86.zip + - IF %PHP%==1 appveyor DownloadFile https://raw.githubusercontent.com/symfony/binary-utils/master/php_intl-3.0.0-5.3-nts-vc9-x86.zip - IF %PHP%==1 7z x php_intl-3.0.0-5.3-nts-vc9-x86.zip -y >nul - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/apcu/4.0.10/php_apcu-4.0.10-5.3-nts-vc9-x86.zip - IF %PHP%==1 7z x php_apcu-4.0.10-5.3-nts-vc9-x86.zip -y >nul From f31e783fd4a44fe7959aa62a1c4e1d2af9aef2bb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 29 Mar 2016 18:06:47 +0200 Subject: [PATCH 21/83] [Process] Fix stream_select priority when writing to stdin --- .../Component/Process/Pipes/AbstractPipes.php | 14 ++++++-------- src/Symfony/Component/Process/Process.php | 2 +- src/Symfony/Component/Process/ProcessUtils.php | 5 ++++- .../Component/Process/Tests/ProcessTest.php | 18 ++++++++++++++++++ 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Process/Pipes/AbstractPipes.php b/src/Symfony/Component/Process/Pipes/AbstractPipes.php index f2fd35eb43c20..ffa6a88319fb9 100644 --- a/src/Symfony/Component/Process/Pipes/AbstractPipes.php +++ b/src/Symfony/Component/Process/Pipes/AbstractPipes.php @@ -22,10 +22,9 @@ abstract class AbstractPipes implements PipesInterface public $pipes = array(); /** @var string */ - protected $inputBuffer = ''; + private $inputBuffer = ''; /** @var resource|null */ - protected $input; - + private $input; /** @var bool */ private $blocked = true; @@ -91,9 +90,8 @@ protected function write() if (!isset($this->pipes[0])) { return; } - - $e = array(); - $r = null !== $this->input ? array($this->input) : $e; + $input = $this->input; + $r = $e = array(); $w = array($this->pipes[0]); // let's have a look if something changed in streams @@ -110,7 +108,7 @@ protected function write() } } - foreach ($r as $input) { + if ($input) { for (;;) { $data = fread($input, self::CHUNK_SIZE); if (!isset($data[0])) { @@ -124,7 +122,7 @@ protected function write() return array($this->pipes[0]); } } - if (!isset($data[0]) && feof($input)) { + if (feof($input)) { // no more data to read on input resource // use an empty buffer in the next reads $this->input = null; diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 8047ef971dd32..679d33a5e336f 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -158,7 +158,7 @@ public function __construct($commandline, $cwd = null, array $env = null, $input $this->setEnv($env); } - $this->input = $input; + $this->setInput($input); $this->setTimeout($timeout); $this->useFileHandles = '\\' === DIRECTORY_SEPARATOR; $this->pty = false; diff --git a/src/Symfony/Component/Process/ProcessUtils.php b/src/Symfony/Component/Process/ProcessUtils.php index 4f30b630dcfe5..0bd2f6b772f6f 100644 --- a/src/Symfony/Component/Process/ProcessUtils.php +++ b/src/Symfony/Component/Process/ProcessUtils.php @@ -80,7 +80,7 @@ public static function escapeArgument($argument) * @param string $caller The name of method call that validates the input * @param mixed $input The input to validate * - * @return string The validated input + * @return mixed The validated input * * @throws InvalidArgumentException In case the input is not valid * @@ -92,6 +92,9 @@ public static function validateInput($caller, $input) if (is_resource($input)) { return $input; } + if (is_string($input)) { + return $input; + } if (is_scalar($input)) { return (string) $input; } diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index ae5e971787c3d..2caa5b995e6a9 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -209,6 +209,24 @@ public function testSetStreamAsInput($code, $size) $this->assertEquals($expectedLength, strlen($p->getErrorOutput())); } + public function testLiveStreamAsInput() + { + $stream = fopen('php://memory', 'r+'); + fwrite($stream, 'hello'); + rewind($stream); + + $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('stream_copy_to_stream(STDIN, STDOUT);'))); + $p->setInput($stream); + $p->start(function ($type, $data) use ($stream) { + if ('hello' === $data) { + fclose($stream); + } + }); + $p->wait(); + + $this->assertSame('hello', $p->getOutput()); + } + /** * @expectedException \Symfony\Component\Process\Exception\LogicException * @expectedExceptionMessage Input can not be set while the process is running. From 5fd054e282edfc3976dfe4f5661300fd63726391 Mon Sep 17 00:00:00 2001 From: annesosensio Date: Thu, 31 Mar 2016 10:26:29 +0200 Subject: [PATCH 22/83] [Process] use __METHOD__ where applicable --- src/Symfony/Component/Process/Process.php | 2 +- src/Symfony/Component/Process/ProcessBuilder.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 30313c0318336..7ea27ffbc2e5c 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -877,7 +877,7 @@ public function setStdin($stdin) throw new LogicException('STDIN can not be set while the process is running.'); } - $this->stdin = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $stdin); + $this->stdin = ProcessUtils::validateInput(__METHOD__, $stdin); return $this; } diff --git a/src/Symfony/Component/Process/ProcessBuilder.php b/src/Symfony/Component/Process/ProcessBuilder.php index 868d284338866..75191f744f342 100644 --- a/src/Symfony/Component/Process/ProcessBuilder.php +++ b/src/Symfony/Component/Process/ProcessBuilder.php @@ -156,7 +156,7 @@ public function setEnv($name, $value) */ public function setInput($stdin) { - $this->stdin = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $stdin); + $this->stdin = ProcessUtils::validateInput(__METHOD__, $stdin); return $this; } From ab8dc0c9d3fcc059c68a196e071d7b006ca41b2a Mon Sep 17 00:00:00 2001 From: "Ariel J. Birnbaum" Date: Tue, 22 Mar 2016 14:30:07 +0100 Subject: [PATCH 23/83] Optimize ReplaceAliasByActualDefinitionPass Previous implementation passed over every alias and every definition, for every alias (n*(n+m) runtime). New implementation passes once over all aliases and once over all definitions (n+m). Also removing needless "restart" logic --- it has no real effect in either case. --- .../ReplaceAliasByActualDefinitionPass.php | 129 +++++++++--------- 1 file changed, 61 insertions(+), 68 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php index 734761de269a2..94121889fe9e9 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.php @@ -25,7 +25,6 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface { private $compiler; private $formatter; - private $sourceId; /** * Process the Container to replace aliases with service definitions. @@ -36,105 +35,99 @@ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface */ public function process(ContainerBuilder $container) { + // Setup $this->compiler = $container->getCompiler(); $this->formatter = $this->compiler->getLoggingFormatter(); - - foreach ($container->getAliases() as $id => $alias) { - $aliasId = (string) $alias; - - if ('service_container' === $aliasId) { + // First collect all alias targets that need to be replaced + $seenAliasTargets = array(); + $replacements = array(); + foreach ($container->getAliases() as $definitionId => $target) { + $targetId = (string) $target; + // Special case: leave this target alone + if ('service_container' === $targetId) { continue; } - + // Check if target needs to be replaces + if (isset($replacements[$targetId])) { + $container->setAlias($definitionId, $replacements[$targetId]); + } + // No neeed to process the same target twice + if (isset($seenAliasTargets[$targetId])) { + continue; + } + // Process new target + $seenAliasTargets[$targetId] = true; try { - $definition = $container->getDefinition($aliasId); + $definition = $container->getDefinition($targetId); } catch (InvalidArgumentException $e) { - throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $id, $alias), null, $e); + throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $definitionId, $targetId), null, $e); } - if ($definition->isPublic()) { continue; } - + // Remove private definition and schedule for replacement $definition->setPublic(true); - $container->setDefinition($id, $definition); - $container->removeDefinition($aliasId); - - $this->updateReferences($container, $aliasId, $id); - - // we have to restart the process due to concurrent modification of - // the container - $this->process($container); - - break; + $container->setDefinition($definitionId, $definition); + $container->removeDefinition($targetId); + $replacements[$targetId] = $definitionId; } - } - - /** - * Updates references to remove aliases. - * - * @param ContainerBuilder $container The container - * @param string $currentId The alias identifier being replaced - * @param string $newId The id of the service the alias points to - */ - private function updateReferences($container, $currentId, $newId) - { - foreach ($container->getAliases() as $id => $alias) { - if ($currentId === (string) $alias) { - $container->setAlias($id, $newId); - } - } - - foreach ($container->getDefinitions() as $id => $definition) { - $this->sourceId = $id; - - $definition->setArguments( - $this->updateArgumentReferences($definition->getArguments(), $currentId, $newId) - ); - - $definition->setMethodCalls( - $this->updateArgumentReferences($definition->getMethodCalls(), $currentId, $newId) - ); - - $definition->setProperties( - $this->updateArgumentReferences($definition->getProperties(), $currentId, $newId) - ); - - $definition->setFactoryService($this->updateFactoryServiceReference($definition->getFactoryService(), $currentId, $newId)); + // Now replace target instances in all definitions + foreach ($container->getDefinitions() as $definitionId => $definition) { + $definition->setArguments($this->updateArgumentReferences($replacements, $definitionId, $definition->getArguments())); + $definition->setMethodCalls($this->updateArgumentReferences($replacements, $definitionId, $definition->getMethodCalls())); + $definition->setProperties($this->updateArgumentReferences($replacements, $definitionId, $definition->getProperties())); + $definition->setFactoryService($this->updateFactoryReferenceId($replacements, $definition->getFactoryService())); } } /** - * Updates argument references. + * Recursively updates references in an array. * - * @param array $arguments An array of Arguments - * @param string $currentId The alias identifier - * @param string $newId The identifier the alias points to + * @param array $replacements Table of aliases to replace + * @param string $definitionId Identifier of this definition + * @param array $arguments Where to replace the aliases * * @return array */ - private function updateArgumentReferences(array $arguments, $currentId, $newId) + private function updateArgumentReferences(array $replacements, $definitionId, array $arguments) { foreach ($arguments as $k => $argument) { + // Handle recursion step if (is_array($argument)) { - $arguments[$k] = $this->updateArgumentReferences($argument, $currentId, $newId); - } elseif ($argument instanceof Reference) { - if ($currentId === (string) $argument) { - $arguments[$k] = new Reference($newId, $argument->getInvalidBehavior()); - $this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $this->sourceId, $currentId, $newId)); - } + $arguments[$k] = $this->updateArgumentReferences($replacements, $definitionId, $argument); + continue; } + // Skip arguments that don't need replacement + if (!$argument instanceof Reference) { + continue; + } + $referenceId = (string) $argument; + if (!isset($replacements[$referenceId])) { + continue; + } + // Perform the replacement + $newId = $replacements[$referenceId]; + $arguments[$k] = new Reference($newId, $argument->getInvalidBehavior()); + $this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $definitionId, $referenceId, $newId)); } return $arguments; } - private function updateFactoryServiceReference($factoryService, $currentId, $newId) + /** + * Returns the updated reference for the factory service. + * + * @param array $replacements Table of aliases to replace + * @param string|null $referenceId Factory service reference identifier + * + * @return string|null + */ + private function updateFactoryReferenceId(array $replacements, $referenceId) { - if (null === $factoryService) { + if (null === $referenceId) { return; } - return $currentId === $factoryService ? $newId : $factoryService; + return isset($replacements[$referenceId]) ? $replacements[$referenceId] : $referenceId; } } From ba1cd26237adce6757fab28bc0ad7d1b4d776b6b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 31 Mar 2016 12:00:43 +0200 Subject: [PATCH 24/83] fixed CS --- src/Symfony/Component/Routing/Generator/UrlGenerator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 978280f776413..939ba5f3636eb 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -187,15 +187,15 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa if ('' === $url) { $url = '/'; - } else if (preg_match($this->urlEncodingSkipRegexp, $url)) { - // the contexts base URL is already encoded (see Symfony\Component\HttpFoundation\Request) + } elseif (preg_match($this->urlEncodingSkipRegexp, $url)) { + // the context base URL is already encoded (see Symfony\Component\HttpFoundation\Request) $url = strtr(rawurlencode($url), $this->decodedChars); } // the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3 // so we need to encode them as they are not used for this purpose here // otherwise we would generate a URI that, when followed by a user agent (e.g. browser), does not match this route - if(false !== strpos($url, '/.')) { + if (false !== strpos($url, '/.')) { $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/')); if ('/..' === substr($url, -3)) { $url = substr($url, 0, -2).'%2E%2E'; From 7df9ca2aebb1886d0d3ec54647aa110d019d5564 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sat, 26 Mar 2016 06:35:01 +0100 Subject: [PATCH 25/83] [Form] fix "prototype" not required when parent form is not required --- .../Extension/Core/Type/CollectionType.php | 3 +- .../Core/Type/CollectionTypeTest.php | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php b/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php index d739a3513ddcf..cf0ed2cb70e9f 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php @@ -55,7 +55,8 @@ public function buildView(FormView $view, FormInterface $form, array $options) )); if ($form->getConfig()->hasAttribute('prototype')) { - $view->vars['prototype'] = $form->getConfig()->getAttribute('prototype')->createView($view); + $prototype = $form->getConfig()->getAttribute('prototype'); + $view->vars['prototype'] = $prototype->setParent($form)->createView($view); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php index 6a5775ea84515..b8d7645a5360f 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php @@ -221,4 +221,46 @@ public function testPrototypeSetNotRequired() $this->assertFalse($form->createView()->vars['required'], 'collection is not required'); $this->assertFalse($form->createView()->vars['prototype']->vars['required'], '"prototype" should not be required'); } + + public function testPrototypeSetNotRequiredIfParentNotRequired() + { + $child = $this->factory->create('collection', array(), array( + 'type' => 'file', + 'allow_add' => true, + 'prototype' => true, + 'prototype_name' => '__test__', + )); + + $parent = $this->factory->create('form', array(), array( + 'required' => false, + )); + + $child->setParent($parent); + $this->assertFalse($parent->createView()->vars['required'], 'Parent is not required'); + $this->assertFalse($child->createView()->vars['required'], 'Child is not required'); + $this->assertFalse($child->createView()->vars['prototype']->vars['required'], '"Prototype" should not be required'); + } + + public function testPrototypeNotOverrideRequiredByEntryOptionsInFavorOfParent() + { + $child = $this->factory->create('collection', array(), array( + 'type' => 'file', + 'allow_add' => true, + 'prototype' => true, + 'prototype_name' => '__test__', + 'options' => array( + 'required' => true, + ), + )); + + $parent = $this->factory->create('form', array(), array( + 'required' => false, + )); + + $child->setParent($parent); + + $this->assertFalse($parent->createView()->vars['required'], 'Parent is not required'); + $this->assertFalse($child->createView()->vars['required'], 'Child is not required'); + $this->assertFalse($child->createView()->vars['prototype']->vars['required'], '"Prototype" should not be required'); + } } From 4f90495e593b43f11adc328f08cd56c3d076169d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 31 Mar 2016 20:43:11 +0200 Subject: [PATCH 26/83] Exclude Bridge\PhpUnit from composer.json by default --- composer.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 571566f802bef..0b3d836e82389 100644 --- a/composer.json +++ b/composer.json @@ -82,7 +82,11 @@ }, "autoload": { "psr-4": { - "Symfony\\Bridge\\": "src/Symfony/Bridge/", + "Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/", + "Symfony\\Bridge\\Monolog\\": "src/Symfony/Bridge/Monolog/", + "Symfony\\Bridge\\ProxyManager\\": "src/Symfony/Bridge/ProxyManager/", + "Symfony\\Bridge\\Swiftmailer\\": "src/Symfony/Bridge/Swiftmailer/", + "Symfony\\Bridge\\Twig\\": "src/Symfony/Bridge/Twig/", "Symfony\\Bundle\\": "src/Symfony/Bundle/", "Symfony\\Component\\": "src/Symfony/Component/" }, @@ -95,6 +99,11 @@ "**/Tests/" ] }, + "autoload-dev": { + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "src/Symfony/Bridge/PhpUnit/" + } + }, "minimum-stability": "dev", "extra": { "branch-alias": { From 7e01187781e6d21a51914f2ded4d3c6fd04c3bb1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 31 Mar 2016 22:06:39 +0200 Subject: [PATCH 27/83] [ci] Skip dns-sensitive tests when DnsMock is not found --- .../Validator/Tests/Constraints/EmailValidatorTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php index b2d74bac6516e..df088cba58397 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php @@ -93,6 +93,7 @@ public function getInvalidEmails() /** * @dataProvider getDnsChecks + * @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts */ public function testDnsChecks($type, $violation) { @@ -126,6 +127,9 @@ public function getDnsChecks() ); } + /** + * @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts + */ public function testHostnameIsProperlyParsed() { DnsMock::withMockedHosts(array('baz.com' => array(array('type' => 'MX')))); From 6dbb11719eeed8dc7447fac2e5b729f2e8ac0c0b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 31 Mar 2016 22:42:22 +0200 Subject: [PATCH 28/83] [VarDumper] Relax tests to pass on appveyor --- .../Component/VarDumper/Tests/Caster/SplCasterTest.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php index e2a8c48fb6376..c6d247e776777 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php @@ -55,12 +55,6 @@ public function getCastFileInfoTests() pathname: "https://google.com/about" extension: "" realPath: false - writable: false - readable: false - executable: false - file: false - dir: false - link: false %A} EOTXT ), From 5c87d766d5f9959dc34a3e314b72c872e591869e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 24 Mar 2016 01:09:44 +0100 Subject: [PATCH 29/83] [FrameworkBundle] Return the invokable service if its name is the class name --- .../Controller/ControllerResolver.php | 4 ++ .../Controller/ControllerResolverTest.php | 43 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php index 6804ded30d0e5..31593b9b80506 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php @@ -78,6 +78,10 @@ protected function createController($controller) */ protected function instantiateController($class) { + if ($this->container->has($class)) { + return $this->container->get($class); + } + $controller = parent::instantiateController($class); if ($controller instanceof ContainerAwareInterface) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php index 76a3489fe1551..b4dc8ada555b6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php @@ -87,6 +87,8 @@ public function testGetControllerService() public function testGetControllerInvokableService() { + $invokableController = new InvokableController('bar'); + $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') @@ -96,7 +98,7 @@ public function testGetControllerInvokableService() $container->expects($this->once()) ->method('get') ->with('foo') - ->will($this->returnValue($this)) + ->will($this->returnValue($invokableController)) ; $resolver = $this->createControllerResolver(null, null, $container); @@ -105,7 +107,33 @@ public function testGetControllerInvokableService() $controller = $resolver->getController($request); - $this->assertInstanceOf(get_class($this), $controller); + $this->assertEquals($invokableController, $controller); + } + + public function testGetControllerInvokableServiceWithClassNameAsName() + { + $invokableController = new InvokableController('bar'); + $className = __NAMESPACE__.'\InvokableController'; + + $container = $this->createMockContainer(); + $container->expects($this->once()) + ->method('has') + ->with($className) + ->will($this->returnValue(true)) + ; + $container->expects($this->once()) + ->method('get') + ->with($className) + ->will($this->returnValue($invokableController)) + ; + + $resolver = $this->createControllerResolver(null, null, $container); + $request = Request::create('/'); + $request->attributes->set('_controller', $className); + + $controller = $resolver->getController($request); + + $this->assertEquals($invokableController, $controller); } /** @@ -178,3 +206,14 @@ public function __invoke() { } } + +class InvokableController +{ + public function __construct($bar) // mandatory argument to prevent automatic instantiation + { + } + + public function __invoke() + { + } +} From efc1de77868a3a5e1a5f82d2f78d408136b03c09 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 1 Apr 2016 08:10:39 +0200 Subject: [PATCH 30/83] skipped dns-sensitive tests when DnsMock is not found --- .../Component/Validator/Tests/Constraints/UrlValidatorTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index fab7cf18675b5..62d53af8a09a1 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -194,6 +194,7 @@ public function getValidCustomUrls() /** * @dataProvider getCheckDns + * @requires function Symfony\Bridge\PhpUnit\DnsMock::withMockedHosts */ public function testCheckDns($violation) { From d583ec3543cec587533292fd1ad92fd09f4a9a54 Mon Sep 17 00:00:00 2001 From: Krzysztof Piasecki Date: Fri, 1 Apr 2016 08:53:42 +0200 Subject: [PATCH 31/83] Lower complexity of Form:isValid() --- src/Symfony/Component/Form/Form.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 0f68dc851a58f..47c38c5718b06 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -766,11 +766,7 @@ public function isValid() return true; } - if (count($this->getErrors(true)) > 0) { - return false; - } - - return true; + return 0 === count($this->getErrors(true)); } /** From cbcac5632b0b1148e91ca5bbdd1957e64cf0947a Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Fri, 1 Apr 2016 13:54:44 +0200 Subject: [PATCH 32/83] [HttpFoundation] fix phpdoc of UploadedFile --- .../Component/HttpFoundation/File/UploadedFile.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php index ad8c796c4224d..e4208327f0e11 100644 --- a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php +++ b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php @@ -50,7 +50,7 @@ class UploadedFile extends File /** * The file size provided by the uploader. * - * @var string + * @var int|null */ private $size; @@ -75,12 +75,12 @@ class UploadedFile extends File * * Calling any other method on an non-valid instance will cause an unpredictable result. * - * @param string $path The full temporary path to the file - * @param string $originalName The original file name - * @param string $mimeType The type of the file as provided by PHP - * @param int $size The file size - * @param int $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants) - * @param bool $test Whether the test mode is active + * @param string $path The full temporary path to the file + * @param string $originalName The original file name + * @param string|null $mimeType The type of the file as provided by PHP; null defaults to application/octet-stream + * @param int|null $size The file size + * @param int|null $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK + * @param bool $test Whether the test mode is active * * @throws FileException If file_uploads is disabled * @throws FileNotFoundException If the file does not exist From 85deb308596e49dcef7eb9cce0969bbe1aff6025 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 1 Apr 2016 16:08:49 +0200 Subject: [PATCH 33/83] Fixed the "hover" state of the profiler sidebar menu --- .../Resources/views/Profiler/profiler.css.twig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig index 91bab657f4994..6e7fb9cb5d54b 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig @@ -515,7 +515,9 @@ tr.status-warning td { margin-bottom: -99999px; {# needed for 'same-height columns' trick #} margin-left: -100%; padding-bottom: 99999px; {# needed for 'same-height columns' trick #} + position: relative; width: 220px; + z-index: 9999; } #sidebar .module { padding: 10px; From b8205a833000b3502c4d0c443a0b33e836b9cf70 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 1 Apr 2016 20:46:52 +0200 Subject: [PATCH 34/83] [travis] Disable hirak/prestissimo for deps=low/high tests --- .composer/composer.json | 3 +- .composer/composer.lock | 8 ++---- .composer/config.json | 3 ++ .travis.yml | 64 +++++++++++++++++++++-------------------- appveyor.yml | 4 +-- 5 files changed, 42 insertions(+), 40 deletions(-) diff --git a/.composer/composer.json b/.composer/composer.json index 655ee13805f47..d69e9f7626d55 100644 --- a/.composer/composer.json +++ b/.composer/composer.json @@ -1,6 +1,5 @@ { "require": { - "php": ">=5.3.7", - "hirak/prestissimo": "^0.1.15" + "hirak/prestissimo": "^0.1.18" } } diff --git a/.composer/composer.lock b/.composer/composer.lock index 8e037ebb4af81..7027e21d9ac4b 100644 --- a/.composer/composer.lock +++ b/.composer/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "aa7aa2d143fd85800595242996021ada", - "content-hash": "51e9161b78dda1fe149a9e9c106be90b", + "hash": "e02685ff7d2409d34fa87e306fc86ec5", + "content-hash": "2854c05c76a78113c693dbbdd3f9c518", "packages": [ { "name": "hirak/prestissimo", @@ -65,8 +65,6 @@ "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, - "platform": { - "php": ">=5.3.7" - }, + "platform": [], "platform-dev": [] } diff --git a/.composer/config.json b/.composer/config.json index 941bc3b56e8cd..436403f601177 100644 --- a/.composer/config.json +++ b/.composer/config.json @@ -2,6 +2,9 @@ "config": { "preferred-install": { "*": "dist" + }, + "prestissimo": { + "insecure": true } } } diff --git a/.travis.yml b/.travis.yml index 50607933e4f42..9177491ebd434 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,43 +35,45 @@ cache: services: mongodb before_install: + - PHP=$TRAVIS_PHP_VERSION # Matrix lines for intermediate PHP versions are skipped for pull requests - - if [[ ! $deps && ! $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && $TRAVIS_PHP_VERSION != hhvm && $TRAVIS_PULL_REQUEST != false ]]; then deps=skip; fi; + - if [[ ! $deps && ! $PHP = ${MIN_PHP%.*} && $PHP != hhvm && $TRAVIS_PULL_REQUEST != false ]]; then deps=skip; skip=1; fi # A sigchild-enabled-PHP is used to test the Process component on the lowest PHP matrix line - - if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then wget http://museum.php.net/php5/php-$MIN_PHP.tar.bz2 -O - | tar -xj; (cd php-$MIN_PHP; ./configure --enable-sigchild --enable-pcntl; make -j2); fi; - - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; else INI_FILE=/etc/hhvm/php.ini; fi; - - echo memory_limit = -1 >> $INI_FILE - - echo session.gc_probability = 0 >> $INI_FILE - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo extension = mongo.so >> $INI_FILE; fi; - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo extension = memcache.so >> $INI_FILE; fi; - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.10 && echo apc.enable_cli = 1 >> $INI_FILE); fi; - - if [[ $TRAVIS_PHP_VERSION = 7.* ]]; then (echo yes | pecl install -f apcu-5.1.2 && echo apc.enable_cli = 1 >> $INI_FILE); fi; - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then pecl install -f memcached-2.1.0; fi; - - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then echo extension = ldap.so >> $INI_FILE; fi; - - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then phpenv config-rm xdebug.ini; fi; - - if [[ $deps != skip ]]; then composer self-update; fi; - - if [[ $deps != skip && $TRAVIS_REPO_SLUG = symfony/symfony ]]; then cp .composer/* ~/.composer/; composer global install; fi; - - if [[ $deps != skip ]]; then ./phpunit install; fi; - - export PHPUNIT=$(readlink -f ./phpunit) + - if [[ ! $deps && $PHP = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then wget http://museum.php.net/php5/php-$MIN_PHP.tar.bz2 -O - | tar -xj; (cd php-$MIN_PHP; ./configure --enable-sigchild --enable-pcntl; make -j2); fi + - if [[ $PHP != hhvm ]]; then INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; else INI_FILE=/etc/hhvm/php.ini; fi + - if [[ ! $skip ]]; then echo memory_limit = -1 >> $INI_FILE; fi + - if [[ ! $skip ]]; then echo session.gc_probability = 0 >> $INI_FILE; fi + - if [[ ! $skip && $PHP = 5.* ]]; then echo extension = mongo.so >> $INI_FILE; fi + - if [[ ! $skip && $PHP = 5.* ]]; then echo extension = memcache.so >> $INI_FILE; fi + - if [[ ! $skip && $PHP = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.10 && echo apc.enable_cli = 1 >> $INI_FILE); fi + - if [[ ! $skip && $PHP = 7.* ]]; then (echo yes | pecl install -f apcu-5.1.2 && echo apc.enable_cli = 1 >> $INI_FILE); fi + - if [[ ! $skip && $PHP = 5.* ]]; then pecl install -f memcached-2.1.0; fi + - if [[ ! $skip && $PHP != hhvm ]]; then echo extension = ldap.so >> $INI_FILE; fi + - if [[ ! $skip && $PHP != hhvm ]]; then phpenv config-rm xdebug.ini; fi + - if [[ ! $skip ]]; then composer self-update; fi + - if [[ ! $skip ]]; then cp .composer/* ~/.composer/; composer global install; fi + - if [[ ! $skip ]]; then ./phpunit install; fi + - if [[ ! $skip && $deps ]]; then composer global remove hirak/prestissimo; fi + - if [[ ! $skip ]]; then export PHPUNIT=$(readlink -f ./phpunit); fi install: - - if [[ $deps != skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi; + - if [[ ! $skip ]]; then COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); fi # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components - - if [[ $deps != skip && $deps ]]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $COMPONENTS; fi; + - if [[ ! $skip && $deps ]]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $COMPONENTS; fi # For the master branch when deps=high, the version before master is checked out and tested with the locally patched components - - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//); else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*'); fi; - - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); ./phpunit install; fi; + - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//); else SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*'); fi + - if [[ $deps = high && $TRAVIS_BRANCH = master ]]; then git fetch origin $SYMFONY_VERSION; git checkout -m FETCH_HEAD; COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n'); ./phpunit install; fi # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number than the next one - - if [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]]; then LEGACY=,legacy; fi; - - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev; - - if [[ ! $deps ]]; then composer update; else export SYMFONY_DEPRECATIONS_HELPER=weak; fi; - - if [[ $TRAVIS_BRANCH = master ]]; then export SYMFONY_PHPUNIT_OVERLOAD=1; fi; - - if [[ $TRAVIS_PHP_VERSION != hhvm ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi; + - if [[ $deps = high && ${SYMFONY_VERSION%.*} != $(git show $(git ls-remote --heads | grep -FA1 /$SYMFONY_VERSION | tail -n 1):composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9]*' | head -n 1) ]]; then LEGACY=,legacy; fi + - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev + - if [[ ! $deps ]]; then composer update; else export SYMFONY_DEPRECATIONS_HELPER=weak; fi + - if [[ $TRAVIS_BRANCH = master ]]; then export SYMFONY_PHPUNIT_OVERLOAD=1; fi + - if [[ $PHP != hhvm ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi script: - - if [[ ! $deps ]]; then echo "$COMPONENTS" | parallel --gnu '$PHPUNIT --exclude-group tty,benchmark,intl-data {}'; fi; - - if [[ ! $deps ]]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty; fi; - - if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} ]]; then echo -e "1\\n0" | xargs -I{} sh -c 'echo "\\nPHP --enable-sigchild enhanced={}" && ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/'; fi; - - if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update; $PHPUNIT --exclude-group tty,benchmark,intl-data'$LEGACY; fi; - - if [[ $deps = low ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --prefer-lowest --prefer-stable; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi; - - if [[ $deps = skip ]]; then echo This matrix line is skipped for pull requests.; fi; + - if [[ $skip ]]; then echo -e "\\n\\e[1;34mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"; fi + - if [[ ! $deps ]]; then echo "$COMPONENTS" | parallel --gnu '$PHPUNIT --exclude-group tty,benchmark,intl-data {}'; fi + - if [[ ! $deps ]]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty; fi + - if [[ ! $deps && $PHP = ${MIN_PHP%.*} ]]; then echo -e "1\\n0" | xargs -I{} sh -c 'echo "\\nPHP --enable-sigchild enhanced={}" && ENHANCE_SIGCHLD={} php-$MIN_PHP/sapi/cli/php .phpunit/phpunit-4.8/phpunit --colors=always src/Symfony/Component/Process/'; fi + - if [[ $deps = high ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --no-progress --ansi; $PHPUNIT --exclude-group tty,benchmark,intl-data'$LEGACY; fi + - if [[ $deps = low ]]; then echo "$COMPONENTS" | parallel --gnu -j10% 'cd {}; composer update --no-progress --ansi --prefer-lowest --prefer-stable; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi diff --git a/appveyor.yml b/appveyor.yml index 8491cd23db2fb..58cca771316a9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -53,8 +53,8 @@ install: - copy /Y php.ini-max php.ini - cd c:\projects\symfony - mkdir %APPDATA%\Composer - - IF %APPVEYOR_REPO_NAME%==symfony/symfony copy /Y .composer\* %APPDATA%\Composer\ - - IF %APPVEYOR_REPO_NAME%==symfony/symfony composer global install --no-progress --ansi || echo curl.cainfo needs PHP 5.3.7 + - copy /Y .composer\* %APPDATA%\Composer\ + - composer global install --no-progress --ansi - php phpunit install - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) - composer update --no-progress --ansi From c3c092de0f51f442b1c4287fdac17c0b4bf77468 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Mon, 4 Apr 2016 10:38:46 +0200 Subject: [PATCH 35/83] [FrameworkBundle] fixes grammar in container:debug command manual. --- .../Bundle/FrameworkBundle/Command/ContainerDebugCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index 67d7451fb565f..d8fde9fe58000 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -75,7 +75,7 @@ protected function configure() php %command.full_name% --parameters -Display a specific parameter by specifying his name with the --parameter option: +Display a specific parameter by specifying its name with the --parameter option: php %command.full_name% --parameter=kernel.debug EOF From a30e1662d865cce9212e0f60dd48f825bab87148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Sun, 3 Apr 2016 23:45:45 +0200 Subject: [PATCH 36/83] [EventDispatcher] Try first if the event is Stopped --- src/Symfony/Component/EventDispatcher/EventDispatcher.php | 2 +- .../Component/HttpKernel/Debug/TraceableEventDispatcher.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 8ec832e8a99b8..58535f2416340 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -155,10 +155,10 @@ public function removeSubscriber(EventSubscriberInterface $subscriber) protected function doDispatch($listeners, $eventName, Event $event) { foreach ($listeners as $listener) { - call_user_func($listener, $event); if ($event->isPropagationStopped()) { break; } + call_user_func($listener, $event); } } diff --git a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php index 81e17da627eb7..b387c950065d9 100644 --- a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php @@ -136,6 +136,10 @@ public function dispatch($eventName, Event $event = null) $event = new Event(); } + if (null !== $this->logger && $event->isPropagationStopped()) { + $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); + } + $eventId = ++$this->lastEventId; $this->preDispatch($eventName, $eventId, $event); From 59fea72a438a4533ab299c7f17f58741aca4f187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Sun, 3 Apr 2016 22:28:33 +0200 Subject: [PATCH 37/83] [Security] Fixed SwitchUserListener when exiting an impersonication with AnonymousToken If you configure a firewall with switch user with `role: IS_AUTHENTICATED_ANONYMOUSLY` it's impossible to exit the impersonation because the next line `$this->provider->refreshUser($original->getUser())` will fail. It fails because `RefreshUser` expects an instance of `UserInterface` and here it's a string. Therefore, it does not make sense to refresh an Anonymous Token, right ? --- .../Http/Firewall/SwitchUserListener.php | 3 +- .../Http/Firewall/SwitchUserListenerTest.php | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index 79b715aa3cdf4..b983b689a6cf5 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -13,6 +13,7 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; @@ -162,7 +163,7 @@ private function attemptExitUser(Request $request) throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.'); } - if (null !== $this->dispatcher) { + if (null !== $this->dispatcher && $original->getUser() instanceof UserInterface) { $user = $this->provider->refreshUser($original->getUser()); $switchEvent = new SwitchUserEvent($request, $user); $this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent); diff --git a/src/Symfony/Component/Security/Tests/Http/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Tests/Http/Firewall/SwitchUserListenerTest.php index 18527518caa3e..1ee6ea5e523ac 100644 --- a/src/Symfony/Component/Security/Tests/Http/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Tests/Http/Firewall/SwitchUserListenerTest.php @@ -149,6 +149,54 @@ public function testExitUserDispatchesEventWithRefreshedUser() $listener->handle($this->event); } + public function testExitUserDoesNotDispatchEventWithStringUser() + { + $originalUser = 'anon.'; + $refreshedUser = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); + $this + ->userProvider + ->expects($this->never()) + ->method('refreshUser'); + $originalToken = $this->getToken(); + $originalToken + ->expects($this->any()) + ->method('getUser') + ->willReturn($originalUser); + $role = $this + ->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole') + ->disableOriginalConstructor() + ->getMock(); + $role + ->expects($this->any()) + ->method('getSource') + ->willReturn($originalToken); + $this + ->securityContext + ->expects($this->any()) + ->method('getToken') + ->willReturn($this->getToken(array($role))); + $this + ->request + ->expects($this->any()) + ->method('get') + ->with('_switch_user') + ->willReturn('_exit'); + $this + ->request + ->expects($this->any()) + ->method('getUri') + ->willReturn('/'); + + $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + $dispatcher + ->expects($this->never()) + ->method('dispatch') + ; + + $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager, null, '_switch_user', 'ROLE_ALLOWED_TO_SWITCH', $dispatcher); + $listener->handle($this->event); + } + /** * @expectedException \Symfony\Component\Security\Core\Exception\AccessDeniedException */ From 472a7bffee94dd2617995af1464f7713beea95a7 Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Thu, 31 Mar 2016 17:27:25 +0200 Subject: [PATCH 38/83] Detect CLI color support for Windows 10 build 10586 --- src/Symfony/Component/Console/Output/StreamOutput.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Output/StreamOutput.php b/src/Symfony/Component/Console/Output/StreamOutput.php index cc39ea108ce3d..ceb6c971bb198 100644 --- a/src/Symfony/Component/Console/Output/StreamOutput.php +++ b/src/Symfony/Component/Console/Output/StreamOutput.php @@ -85,7 +85,7 @@ protected function doWrite($message, $newline) * * Colorization is disabled if not supported by the stream: * - * - Windows without Ansicon, ConEmu or Mintty + * - Windows before 10.0.10586 without Ansicon, ConEmu or Mintty * - non tty consoles * * @return bool true if the stream supports colorization, false otherwise @@ -94,7 +94,11 @@ protected function hasColorSupport() { // @codeCoverageIgnoreStart if (DIRECTORY_SEPARATOR === '\\') { - return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM'); + return + 0 >= version_compare('10.0.10586', PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD) + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM'); } return function_exists('posix_isatty') && @posix_isatty($this->stream); From 5f5a71770b35f59c247cd7b2dadee23382ec32fe Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Fri, 1 Apr 2016 19:41:59 +0200 Subject: [PATCH 39/83] Windows 10 version check in just one line --- .../Bridge/PhpUnit/DeprecationErrorHandler.php | 6 +++++- src/Symfony/Component/VarDumper/Dumper/CliDumper.php | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index b06b66bf34289..21fbc30ee68dd 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -160,7 +160,11 @@ public static function register($mode = false) private static function hasColorSupport() { if ('\\' === DIRECTORY_SEPARATOR) { - return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM'); + return + 0 >= version_compare('10.0.10586', PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD) + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM'); } return defined('STDOUT') && function_exists('posix_isatty') && @posix_isatty(STDOUT); diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index cbdef90dd4a68..5e8a59cce91bd 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -58,8 +58,8 @@ public function __construct($output = null, $charset = null) { parent::__construct($output, $charset); - if ('\\' === DIRECTORY_SEPARATOR && false !== @getenv('ANSICON')) { - // Use only the base 16 xterm colors when using ANSICON + if ('\\' === DIRECTORY_SEPARATOR && 'ON' !== @getenv('ConEmuANSI') && 'xterm' !== @getenv('TERM')) { + // Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI $this->setStyles(array( 'default' => '31', 'num' => '1;34', @@ -448,7 +448,12 @@ protected function supportsColors() } if ('\\' === DIRECTORY_SEPARATOR) { - static::$defaultColors = @(false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM')); + static::$defaultColors = @( + 0 >= version_compare('10.0.10586', PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD) + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM') + ); } elseif (function_exists('posix_isatty')) { $h = stream_get_meta_data($this->outputStream) + array('wrapper_type' => null); $h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'wb') : $this->outputStream; From c8efc4dfc2a451ec05f74172f6c85121239deaef Mon Sep 17 00:00:00 2001 From: Arjen van der Meijden Date: Mon, 4 Apr 2016 20:48:53 +0200 Subject: [PATCH 40/83] [Logging] Add support for firefox in ChromePhpHandler --- src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php b/src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php index 97ce3089837ce..43f54b536ae48 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php @@ -42,7 +42,7 @@ public function onKernelResponse(FilterResponseEvent $event) return; } - if (!preg_match('{\bChrome/\d+[\.\d+]*\b}', $event->getRequest()->headers->get('User-Agent'))) { + if (!preg_match('{\b(?:Chrome/\d+(?:\.\d+)*|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}', $event->getRequest()->headers->get('User-Agent'))) { $this->sendHeaders = false; $this->headers = array(); From 6bfbb2e25f554d552a65b979e6d7adceca3c4683 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Tue, 5 Apr 2016 11:24:23 +0200 Subject: [PATCH 41/83] [HttpFoundation] Improve phpdoc Improve the phpdoc for the `$default` parameter of the `get()` method. It wasn't clear when the default value would be used (whether the key would not exist or the value was `null` or nullish). The comment is now in sync with `Symfony\Component\HttpFoundation\ParameterBag::get()`. --- src/Symfony/Component/HttpFoundation/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 0423323b62fc2..84177087c95fd 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -674,7 +674,7 @@ public static function getHttpMethodParameterOverride() * public property instead (query, attributes, request). * * @param string $key the key - * @param mixed $default the default value + * @param mixed $default the default value if the parameter key does not exist * @param bool $deep is parameter deep in multidimensional array * * @return mixed From 2b30d486db1c7079efcd204c95467deec4726a8c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 5 Apr 2016 18:42:48 +0200 Subject: [PATCH 42/83] [PropertyAccess] Fix regression --- .../PropertyAccess/PropertyAccessor.php | 1 + .../Tests/Fixtures/TestClass.php | 176 ++++++++++++++++++ .../Tests/PropertyAccessorTest.php | 11 ++ 3 files changed, 188 insertions(+) create mode 100644 src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClass.php diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 42e3671754891..46e79231226fb 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -181,6 +181,7 @@ public function setValue(&$objectOrArray, $propertyPath, $value) if ($propertyPath->isIndex($i)) { if ($overwrite = !isset($zval[self::REF])) { $ref = &$zval[self::REF]; + $ref = $zval[self::VALUE]; } $this->writeIndex($zval, $property, $value); if ($overwrite) { diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClass.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClass.php new file mode 100644 index 0000000000000..7b1b927529afe --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClass.php @@ -0,0 +1,176 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class TestClass +{ + public $publicProperty; + protected $protectedProperty; + private $privateProperty; + + private $publicAccessor; + private $publicMethodAccessor; + private $publicGetSetter; + private $publicAccessorWithDefaultValue; + private $publicAccessorWithRequiredAndDefaultValue; + private $publicAccessorWithMoreRequiredParameters; + private $publicIsAccessor; + private $publicHasAccessor; + private $publicGetter; + + public function __construct($value) + { + $this->publicProperty = $value; + $this->publicAccessor = $value; + $this->publicMethodAccessor = $value; + $this->publicGetSetter = $value; + $this->publicAccessorWithDefaultValue = $value; + $this->publicAccessorWithRequiredAndDefaultValue = $value; + $this->publicAccessorWithMoreRequiredParameters = $value; + $this->publicIsAccessor = $value; + $this->publicHasAccessor = $value; + $this->publicGetter = $value; + } + + public function setPublicAccessor($value) + { + $this->publicAccessor = $value; + } + + public function setPublicAccessorWithDefaultValue($value = null) + { + $this->publicAccessorWithDefaultValue = $value; + } + + public function setPublicAccessorWithRequiredAndDefaultValue($value, $optional = null) + { + $this->publicAccessorWithRequiredAndDefaultValue = $value; + } + + public function setPublicAccessorWithMoreRequiredParameters($value, $needed) + { + $this->publicAccessorWithMoreRequiredParameters = $value; + } + + public function getPublicAccessor() + { + return $this->publicAccessor; + } + + public function getPublicAccessorWithDefaultValue() + { + return $this->publicAccessorWithDefaultValue; + } + + public function getPublicAccessorWithRequiredAndDefaultValue() + { + return $this->publicAccessorWithRequiredAndDefaultValue; + } + + public function getPublicAccessorWithMoreRequiredParameters() + { + return $this->publicAccessorWithMoreRequiredParameters; + } + + public function setPublicIsAccessor($value) + { + $this->publicIsAccessor = $value; + } + + public function isPublicIsAccessor() + { + return $this->publicIsAccessor; + } + + public function setPublicHasAccessor($value) + { + $this->publicHasAccessor = $value; + } + + public function hasPublicHasAccessor() + { + return $this->publicHasAccessor; + } + + public function publicGetSetter($value = null) + { + if (null !== $value) { + $this->publicGetSetter = $value; + } + + return $this->publicGetSetter; + } + + public function getPublicMethodMutator() + { + return $this->publicGetSetter; + } + + protected function setProtectedAccessor($value) + { + } + + protected function getProtectedAccessor() + { + return 'foobar'; + } + + protected function setProtectedIsAccessor($value) + { + } + + protected function isProtectedIsAccessor() + { + return 'foobar'; + } + + protected function setProtectedHasAccessor($value) + { + } + + protected function hasProtectedHasAccessor() + { + return 'foobar'; + } + + private function setPrivateAccessor($value) + { + } + + private function getPrivateAccessor() + { + return 'foobar'; + } + + private function setPrivateIsAccessor($value) + { + } + + private function isPrivateIsAccessor() + { + return 'foobar'; + } + + private function setPrivateHasAccessor($value) + { + } + + private function hasPrivateHasAccessor() + { + return 'foobar'; + } + + public function getPublicGetter() + { + return $this->publicGetter; + } +} diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 8429b7f3d5c73..889c3491c2b83 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -15,6 +15,7 @@ use Symfony\Component\PropertyAccess\Tests\Fixtures\Author; use Symfony\Component\PropertyAccess\Tests\Fixtures\Magician; use Symfony\Component\PropertyAccess\Tests\Fixtures\MagicianCall; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClass; use Symfony\Component\PropertyAccess\Tests\Fixtures\Ticket5775Object; use Symfony\Component\PropertyAccess\Tests\Fixtures\TypeHinted; @@ -422,4 +423,14 @@ public function testSetTypeHint() $this->propertyAccessor->setValue($object, 'date', $date); $this->assertSame($date, $object->getDate()); } + + public function testArrayNotBeeingOverwritten() + { + $value = array('value1' => 'foo', 'value2' => 'bar'); + $object = new TestClass($value); + + $this->propertyAccessor->setValue($object, 'publicAccessor[value2]', 'baz'); + $this->assertSame('baz', $this->propertyAccessor->getValue($object, 'publicAccessor[value2]')); + $this->assertSame(array('value1' => 'foo', 'value2' => 'baz'), $object->getPublicAccessor()); + } } From 4b78d0337954bd48c33a3f5d6060c5800259c8e4 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 5 Apr 2016 20:28:19 +0200 Subject: [PATCH 43/83] mock the proper method --- .../Http/Tests/Firewall/SwitchUserListenerTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php index bca2c4a333917..b004b2754d6c7 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php @@ -187,9 +187,15 @@ public function testExitUserDoesNotDispatchEventWithStringUser() $this ->request ->expects($this->any()) - ->method('all') + ->method('get') ->with('_switch_user') ->willReturn('_exit'); + $this + ->request + ->query + ->expects($this->any()) + ->method('all') + ->will($this->returnValue(array())); $this ->request ->expects($this->any()) From d5964aee96627eebd950153795a1f67e8b91e6f3 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 5 Apr 2016 20:29:19 +0200 Subject: [PATCH 44/83] remove unused variable --- .../Security/Tests/Http/Firewall/SwitchUserListenerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Security/Tests/Http/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Tests/Http/Firewall/SwitchUserListenerTest.php index 1ee6ea5e523ac..4e795c8d62ed6 100644 --- a/src/Symfony/Component/Security/Tests/Http/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Tests/Http/Firewall/SwitchUserListenerTest.php @@ -152,7 +152,6 @@ public function testExitUserDispatchesEventWithRefreshedUser() public function testExitUserDoesNotDispatchEventWithStringUser() { $originalUser = 'anon.'; - $refreshedUser = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); $this ->userProvider ->expects($this->never()) From f82a25f288596317a31d0c230cd7a0fdf49ada43 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 5 Apr 2016 20:37:03 +0200 Subject: [PATCH 45/83] fix tests (use non-deprecated options) * reference form type by its FQCN instead of its string name * use the `entry_type` and `entry_options` options instead of the deprecated `type` and `options` options --- .../Extension/Core/Type/CollectionTypeTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php index 2b928cac7cba3..b02fef221ed12 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php @@ -365,14 +365,14 @@ public function testPrototypeSetNotRequired() public function testPrototypeSetNotRequiredIfParentNotRequired() { - $child = $this->factory->create('collection', array(), array( - 'type' => 'file', + $child = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\CollectionType', array(), array( + 'entry_type' => 'Symfony\Component\Form\Extension\Core\Type\FileType', 'allow_add' => true, 'prototype' => true, 'prototype_name' => '__test__', )); - $parent = $this->factory->create('form', array(), array( + $parent = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', array(), array( 'required' => false, )); @@ -384,17 +384,17 @@ public function testPrototypeSetNotRequiredIfParentNotRequired() public function testPrototypeNotOverrideRequiredByEntryOptionsInFavorOfParent() { - $child = $this->factory->create('collection', array(), array( - 'type' => 'file', + $child = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\CollectionType', array(), array( + 'entry_type' => 'Symfony\Component\Form\Extension\Core\Type\FileType', 'allow_add' => true, 'prototype' => true, 'prototype_name' => '__test__', - 'options' => array( + 'entry_options' => array( 'required' => true, ), )); - $parent = $this->factory->create('form', array(), array( + $parent = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', array(), array( 'required' => false, )); From da8a19728b42d8ced90d4d3e1bd5202cd980ae38 Mon Sep 17 00:00:00 2001 From: Sergey Fedotov Date: Tue, 5 Apr 2016 22:57:40 +0300 Subject: [PATCH 46/83] Remove unnecessary option assignment --- .../Component/Form/Extension/Core/Type/CollectionType.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php b/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php index cf0ed2cb70e9f..948e5a6b372e2 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php @@ -28,7 +28,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) { if ($options['allow_add'] && $options['prototype']) { $prototype = $builder->create($options['prototype_name'], $options['type'], array_replace(array( - 'required' => $options['required'], 'label' => $options['prototype_name'].'label__', ), $options['options'])); $builder->setAttribute('prototype', $prototype->getForm()); From 58276a274e2e6981b0dc83c171cf965bd6e9e3f0 Mon Sep 17 00:00:00 2001 From: Matt Wells Date: Wed, 6 Apr 2016 11:37:55 +0100 Subject: [PATCH 47/83] Fix Dom Crawler select option with empty value --- .../Component/DomCrawler/Field/ChoiceFormField.php | 3 ++- .../DomCrawler/Tests/Field/ChoiceFormFieldTest.php | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php index 12194091e0da5..4f378a4dd806e 100644 --- a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php +++ b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php @@ -259,7 +259,8 @@ private function buildOptionValue($node) { $option = array(); - $defaultValue = (isset($node->nodeValue) && !empty($node->nodeValue)) ? $node->nodeValue : '1'; + $defaultDefaultValue = 'select' === $this->node->nodeName ? '' : '1'; + $defaultValue = (isset($node->nodeValue) && !empty($node->nodeValue)) ? $node->nodeValue : $defaultDefaultValue; $option['value'] = $node->hasAttribute('value') ? $node->getAttribute('value') : $defaultValue; $option['disabled'] = $node->hasAttribute('disabled'); diff --git a/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php b/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php index ce87b15c2ed59..0afbe6e7e2cce 100644 --- a/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php @@ -336,6 +336,14 @@ public function testOptionWithNoValue() $this->assertEquals('foo', $field->getValue(), '->select() changes the selected option'); } + public function testSelectWithEmptyValue() + { + $node = $this->createSelectNodeWithEmptyOption(array('' => true, 'Female' => false, 'Male' => false)); + $field = new ChoiceFormField($node); + + $this->assertSame('', $field->getValue()); + } + protected function createSelectNode($options, $attributes = array(), $selectedAttrText = 'selected') { $document = new \DOMDocument(); From 9802a41b3cdd90bc9a4e625d6043859153ce67de Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 5 Apr 2016 15:46:37 +0200 Subject: [PATCH 48/83] [DependencyInjection] Resolve aliases before removing abstract services + add tests --- .../Compiler/PassConfig.php | 5 ++-- .../Tests/ContainerBuilderTest.php | 15 ++++++++++++ .../Tests/Fixtures/xml/services5.xml | 6 ++++- .../Tests/Loader/XmlFileLoaderTest.php | 24 +++++++++++++++++-- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 7fb47f82b3dd4..a28262ec4bf93 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -59,8 +59,8 @@ public function __construct() $this->removingPasses = array( new RemovePrivateAliasesPass(), - new RemoveAbstractDefinitionsPass(), new ReplaceAliasByActualDefinitionPass(), + new RemoveAbstractDefinitionsPass(), new RepeatedPass(array( new AnalyzeServiceReferencesPass(), new InlineServiceDefinitionsPass(), @@ -103,8 +103,7 @@ public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_O throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type)); } - $passes = &$this->$property; - $passes[] = $pass; + $this->{$property}[] = $pass; } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 5719dc68ea2a4..6d3360f0dde14 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -707,6 +707,21 @@ public function testExtensionConfig() $this->assertEquals(array($second, $first), $configs); } + public function testAbstractAlias() + { + $container = new ContainerBuilder(); + + $abstract = new Definition('AbstractClass'); + $abstract->setAbstract(true); + + $container->setDefinition('abstract_service', $abstract); + $container->setAlias('abstract_alias', 'abstract_service'); + + $container->compile(); + + $this->assertSame('abstract_service', (string) $container->getAlias('abstract_alias')); + } + public function testLazyLoadedService() { $loader = new ClosureLoader($container = new ContainerBuilder()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services5.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services5.xml index acb93e748e483..347df977dd26b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services5.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services5.xml @@ -14,8 +14,12 @@ - + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index e5dfa2a13e6bd..38ee13d5ff73e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -121,7 +121,7 @@ public function testLoadAnonymousServices() $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); $loader->load('services5.xml'); $services = $container->getDefinitions(); - $this->assertCount(4, $services, '->load() attributes unique ids to anonymous services'); + $this->assertCount(6, $services, '->load() attributes unique ids to anonymous services'); // anonymous service as an argument $args = $services['foo']->getArguments(); @@ -130,6 +130,7 @@ public function testLoadAnonymousServices() $this->assertTrue(isset($services[(string) $args[0]]), '->load() makes a reference to the created ones'); $inner = $services[(string) $args[0]]; $this->assertEquals('BarClass', $inner->getClass(), '->load() uses the same configuration as for the anonymous ones'); + $this->assertFalse($inner->isPublic()); // inner anonymous services $args = $inner->getArguments(); @@ -138,6 +139,7 @@ public function testLoadAnonymousServices() $this->assertTrue(isset($services[(string) $args[0]]), '->load() makes a reference to the created ones'); $inner = $services[(string) $args[0]]; $this->assertEquals('BazClass', $inner->getClass(), '->load() uses the same configuration as for the anonymous ones'); + $this->assertFalse($inner->isPublic()); // anonymous service as a property $properties = $services['foo']->getProperties(); @@ -145,7 +147,25 @@ public function testLoadAnonymousServices() $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Reference', $property, '->load() converts anonymous services to references to "normal" services'); $this->assertTrue(isset($services[(string) $property]), '->load() makes a reference to the created ones'); $inner = $services[(string) $property]; - $this->assertEquals('BazClass', $inner->getClass(), '->load() uses the same configuration as for the anonymous ones'); + $this->assertEquals('BuzClass', $inner->getClass(), '->load() uses the same configuration as for the anonymous ones'); + $this->assertFalse($inner->isPublic()); + + // "wild" service + $service = $container->findTaggedServiceIds('biz_tag'); + $this->assertCount(1, $service); + + foreach ($service as $id => $tag) { + $service = $container->getDefinition($id); + } + $this->assertEquals('BizClass', $service->getClass(), '->load() uses the same configuration as for the anonymous ones'); + $this->assertFalse($service->isPublic()); + + // anonymous services are shared when using decoration definitions + $container->compile(); + $services = $container->getDefinitions(); + $fooArgs = $services['foo']->getArguments(); + $barArgs = $services['bar']->getArguments(); + $this->assertSame($fooArgs[0], $barArgs[0]); } public function testLoadServices() From 467d8c722d0e2699fed9e5db83beec3ade77f3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFck=20Piera?= Date: Thu, 7 Apr 2016 10:55:09 +0200 Subject: [PATCH 49/83] Force profiler toolbar svg display --- .../WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig index 723541fc8298a..d87e81399d412 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig @@ -59,6 +59,7 @@ .sf-toolbarreset svg, .sf-toolbarreset img { height: 20px; + display: inline-block; } .sf-toolbarreset .hide-button { From 3e2c4c9df704d2a1713bb89d03430d3111936a07 Mon Sep 17 00:00:00 2001 From: Simon Sargeant Date: Tue, 5 Apr 2016 22:50:06 +0100 Subject: [PATCH 50/83] [WebProfilerBundle] Fixed error from unset twig variable --- .../Resources/views/Collector/config.html.twig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig index a2a7dff8b49f0..545d34e48697e 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig @@ -50,24 +50,24 @@ - {% if 'n/a' != collector.appname %} + {% if 'n/a' is not same as(collector.appname) %}
Kernel name {{ collector.appname }}
{% endif %} - {% if 'n/a' != collector.env %} + {% if 'n/a' is not same as(collector.env) %}
Environment {{ collector.env }}
{% endif %} - {% if 'n/a' != collector.debug %} + {% if 'n/a' is not same as(collector.debug) %}
Debug - {{ collector.debug ? 'enabled' : 'disabled' }} + {{ collector.debug ? 'enabled' : 'disabled' }}
{% endif %} From b264b66a9098743b27d3242c9318fb07a80f8e29 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Mon, 4 Apr 2016 02:13:10 -0500 Subject: [PATCH 51/83] [Console] Correct time formatting. --- .../Component/Console/Helper/Helper.php | 32 +++++------ .../Console/Tests/Helper/HelperTest.php | 54 +++++++++++++++++++ .../Console/Tests/Helper/ProgressBarTest.php | 6 +-- 3 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 src/Symfony/Component/Console/Tests/Helper/HelperTest.php diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Component/Console/Helper/Helper.php index 156d8dc644cf9..444bbffc768e3 100644 --- a/src/Symfony/Component/Console/Helper/Helper.php +++ b/src/Symfony/Component/Console/Helper/Helper.php @@ -66,26 +66,28 @@ public static function formatTime($secs) { static $timeFormats = array( array(0, '< 1 sec'), - array(2, '1 sec'), - array(59, 'secs', 1), + array(1, '1 sec'), + array(2, 'secs', 1), array(60, '1 min'), - array(3600, 'mins', 60), - array(5400, '1 hr'), - array(86400, 'hrs', 3600), - array(129600, '1 day'), - array(604800, 'days', 86400), + array(120, 'mins', 60), + array(3600, '1 hr'), + array(7200, 'hrs', 3600), + array(86400, '1 day'), + array(172800, 'days', 86400), ); - foreach ($timeFormats as $format) { + foreach ($timeFormats as $index => $format) { if ($secs >= $format[0]) { - continue; + if ((isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0]) + || $index == count($timeFormats) - 1 + ) { + if (2 == count($format)) { + return $format[1]; + } + + return floor($secs / $format[2]).' '.$format[1]; + } } - - if (2 == count($format)) { - return $format[1]; - } - - return ceil($secs / $format[2]).' '.$format[1]; } } diff --git a/src/Symfony/Component/Console/Tests/Helper/HelperTest.php b/src/Symfony/Component/Console/Tests/Helper/HelperTest.php new file mode 100644 index 0000000000000..33fa22051a05d --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Helper/HelperTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use Symfony\Component\Console\Helper\Helper; + +class HelperTest extends \PHPUnit_Framework_TestCase +{ + public function formatTimeProvider() + { + return array( + array(0, '< 1 sec'), + array(1, '1 sec'), + array(2, '2 secs'), + array(59, '59 secs'), + array(60, '1 min'), + array(61, '1 min'), + array(119, '1 min'), + array(120, '2 mins'), + array(121, '2 mins'), + array(3599, '59 mins'), + array(3600, '1 hr'), + array(7199, '1 hr'), + array(7200, '2 hrs'), + array(7201, '2 hrs'), + array(86399, '23 hrs'), + array(86400, '1 day'), + array(86401, '1 day'), + array(172799, '1 day'), + array(172800, '2 days'), + array(172801, '2 days'), + ); + } + + /** + * @dataProvider formatTimeProvider + * + * @param int $secs + * @param string $expectedFormat + */ + public function testFormatTime($secs, $expectedFormat) + { + $this->assertEquals($expectedFormat, Helper::formatTime($secs)); + } +} diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index ffe5bed086348..c6bbe81c98a57 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -591,17 +591,17 @@ public function testAnsiColorsAndEmojis() $this->generateOutput( " \033[44;37m Starting the demo... fingers crossed \033[0m\n". ' 0/15 '.$progress.str_repeat($empty, 26)." 0%\n". - " \xf0\x9f\x8f\x81 1 sec \033[44;37m 0 B \033[0m" + " \xf0\x9f\x8f\x81 < 1 sec \033[44;37m 0 B \033[0m" ). $this->generateOutput( " \033[44;37m Looks good to me... \033[0m\n". ' 4/15 '.str_repeat($done, 7).$progress.str_repeat($empty, 19)." 26%\n". - " \xf0\x9f\x8f\x81 1 sec \033[41;37m 97 KiB \033[0m" + " \xf0\x9f\x8f\x81 < 1 sec \033[41;37m 97 KiB \033[0m" ). $this->generateOutput( " \033[44;37m Thanks, bye \033[0m\n". ' 15/15 '.str_repeat($done, 28)." 100%\n". - " \xf0\x9f\x8f\x81 1 sec \033[41;37m 195 KiB \033[0m" + " \xf0\x9f\x8f\x81 < 1 sec \033[41;37m 195 KiB \033[0m" ), stream_get_contents($output->getStream()) ); From 71841c737cbda8aedf450d5b72ed5de4a70132f4 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Tue, 15 Mar 2016 06:26:43 +0100 Subject: [PATCH 52/83] Revert "[Form] refactor `RadioListMapper::mapDataToForm()`" closes #18173. This reverts commit 8f918e5f84c53826d025cbb1f3a0bfe093acc4e0. --- .../Form/Extension/Core/DataMapper/RadioListMapper.php | 6 ++++-- .../Component/Form/Extension/Core/Type/ChoiceType.php | 8 -------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php b/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php index d08a603b5c90e..19db183a28394 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php +++ b/src/Symfony/Component/Form/Extension/Core/DataMapper/RadioListMapper.php @@ -38,11 +38,13 @@ public function __construct(ChoiceListInterface $choiceList) /** * {@inheritdoc} */ - public function mapDataToForms($data, $radios) + public function mapDataToForms($choice, $radios) { + $valueMap = array_flip($this->choiceList->getValuesForChoices(array($choice))); + foreach ($radios as $radio) { $value = $radio->getConfig()->getOption('value'); - $radio->setData($value === $data ? true : false); + $radio->setData(isset($valueMap[$value]) ? true : false); } } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index 26af37b9ace79..29798d037ac80 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -143,14 +143,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) $event->setData(null); } }); - // For radio lists, pre selection of the choice needs to pre set data - // with the string value so it can be matched in - // {@link \Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper::mapDataToForms()} - $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { - $choiceList = $event->getForm()->getConfig()->getOption('choice_list'); - $value = current($choiceList->getValuesForChoices(array($event->getData()))); - $event->setData((string) $value); - }); } } elseif ($options['multiple']) { // tag with "multiple" option + if ($options['multiple']) { + // tag without "multiple" option + //