From 9c48756a19a930ce4dc13eb47a50b89de9e3b921 Mon Sep 17 00:00:00 2001 From: Iltar van der Berg Date: Thu, 1 Sep 2016 09:08:10 +0200 Subject: [PATCH 01/43] Fixed the nullable support for php 7.1 and below --- .../Controller/ControllerResolver.php | 22 +++++++++++++- .../Controller/ControllerResolverTest.php | 29 +++++++++++++++++++ .../Controller/NullableController.php | 19 ++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/NullableController.php diff --git a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php index 1d7c49607dfe9..c76b57bb6a7db 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php @@ -27,6 +27,15 @@ class ControllerResolver implements ControllerResolverInterface { private $logger; + /** + * If the ...$arg functionality is available. + * + * Requires at least PHP 5.6.0 or HHVM 3.9.1 + * + * @var bool + */ + private $supportsVariadic; + /** * Constructor. * @@ -35,6 +44,8 @@ class ControllerResolver implements ControllerResolverInterface public function __construct(LoggerInterface $logger = null) { $this->logger = $logger; + + $this->supportsVariadic = method_exists('ReflectionParameter', 'isVariadic'); } /** @@ -99,13 +110,20 @@ public function getArguments(Request $request, $controller) return $this->doGetArguments($request, $controller, $r->getParameters()); } + /** + * @param Request $request + * @param callable $controller + * @param \ReflectionParameter[] $parameters + * + * @return array The arguments to use when calling the action + */ protected function doGetArguments(Request $request, $controller, array $parameters) { $attributes = $request->attributes->all(); $arguments = array(); foreach ($parameters as $param) { if (array_key_exists($param->name, $attributes)) { - if (PHP_VERSION_ID >= 50600 && $param->isVariadic() && is_array($attributes[$param->name])) { + if ($this->supportsVariadic && $param->isVariadic() && is_array($attributes[$param->name])) { $arguments = array_merge($arguments, array_values($attributes[$param->name])); } else { $arguments[] = $attributes[$param->name]; @@ -114,6 +132,8 @@ protected function doGetArguments(Request $request, $controller, array $paramete $arguments[] = $request; } elseif ($param->isDefaultValueAvailable()) { $arguments[] = $param->getDefaultValue(); + } elseif ($param->allowsNull()) { + $arguments[] = null; } else { if (is_array($controller)) { $repr = sprintf('%s::%s()', get_class($controller[0]), $controller[1]); diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php index 101782e49079e..9aa7e20a9a910 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php @@ -13,6 +13,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Controller\ControllerResolver; +use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\NullableController; use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\VariadicController; use Symfony\Component\HttpFoundation\Request; @@ -222,6 +223,34 @@ public function testCreateControllerCanReturnAnyCallable() $mock->getController($request); } + /** + * @requires PHP 7.1 + */ + public function testGetNullableArguments() + { + $resolver = new ControllerResolver(); + + $request = Request::create('/'); + $request->attributes->set('foo', 'foo'); + $request->attributes->set('bar', new \stdClass()); + $request->attributes->set('mandatory', 'mandatory'); + $controller = array(new NullableController(), 'action'); + $this->assertEquals(array('foo', new \stdClass(), 'value', 'mandatory'), $resolver->getArguments($request, $controller)); + } + + /** + * @requires PHP 7.1 + */ + public function testGetNullableArgumentsWithDefaults() + { + $resolver = new ControllerResolver(); + + $request = Request::create('/'); + $request->attributes->set('mandatory', 'mandatory'); + $controller = array(new NullableController(), 'action'); + $this->assertEquals(array(null, null, 'value', 'mandatory'), $resolver->getArguments($request, $controller)); + } + protected function createControllerResolver(LoggerInterface $logger = null) { return new ControllerResolver($logger); diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/NullableController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/NullableController.php new file mode 100644 index 0000000000000..9db4df7b4c173 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/NullableController.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller; + +class NullableController +{ + public function action(?string $foo, ?\stdClass $bar, ?string $baz = 'value', $mandatory) + { + } +} From be2a6d129131d33e5504091cd540ddb0a82cd6b4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 6 Sep 2016 19:01:26 -0700 Subject: [PATCH 02/43] bumped Symfony version to 2.7.19 --- 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 e0e79545193b2..c6586c02312aa 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.18'; - const VERSION_ID = 20718; + const VERSION = '2.7.19-DEV'; + const VERSION_ID = 20719; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; - const RELEASE_VERSION = 18; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 19; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From bf6691ca4617b8b6da22fc7b19801f82009bae13 Mon Sep 17 00:00:00 2001 From: Matteo Beccati Date: Wed, 7 Sep 2016 13:06:20 +0200 Subject: [PATCH 03/43] Fix #19721 Issue was introduced in #19541 --- .../DateTimeToLocalizedStringTransformer.php | 5 ++++- ...DateTimeToLocalizedStringTransformerTest.php | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php index 51f692755eb6d..d2e5ddba5cd9d 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -134,7 +134,10 @@ public function reverseTransform($value) } // read timestamp into DateTime object - the formatter delivers a timestamp - $dateTime = new \DateTime(sprintf('@%s', $timestamp), new \DateTimeZone($this->outputTimezone)); + $dateTime = new \DateTime(sprintf('@%s', $timestamp)); + // set timezone separately, as it would be ignored if set via the constructor, + // see http://php.net/manual/en/datetime.construct.php + $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index 444cdd4582330..d5abfe7047b5f 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -134,6 +134,23 @@ public function testTransformWithDifferentTimezones() $this->assertEquals($dateTime->format('d.m.Y, H:i'), $transformer->transform($input)); } + public function testReverseTransformWithNoConstructorParameters() + { + $tz = date_default_timezone_get(); + date_default_timezone_set('Europe/Rome'); + + $transformer = new DateTimeToLocalizedStringTransformer(); + + $dateTime = new \DateTime('2010-02-03 04:05'); + + $this->assertEquals( + $dateTime->format('c'), + $transformer->reverseTransform('03.02.2010, 04:05')->format('c') + ); + + date_default_timezone_set($tz); + } + public function testTransformWithDifferentPatterns() { $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, 'MM*yyyy*dd HH|mm|ss'); From d3c613be367c5d3b28de03ef669f3ea0354a37c1 Mon Sep 17 00:00:00 2001 From: Hugo Fonseca Date: Wed, 7 Sep 2016 12:59:03 +0100 Subject: [PATCH 04/43] [Console] fixed PHP7 Errors are now handled and converted to Exceptions --- src/Symfony/Component/Console/Application.php | 15 ++++- .../Console/Tests/ApplicationTest.php | 56 +++++++++++++++++++ src/Symfony/Component/Console/composer.json | 3 +- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 590460ca0de99..c2c13b8aedbd4 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -38,6 +38,7 @@ use Symfony\Component\Console\Event\ConsoleCommandEvent; use Symfony\Component\Console\Event\ConsoleExceptionEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Symfony\Component\Debug\Exception\FatalThrowableError; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -849,17 +850,25 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI if ($event->commandShouldRun()) { try { + $e = null; $exitCode = $command->run($input, $output); - } catch (\Exception $e) { + } catch (\Exception $x) { + $e = $x; + } catch (\Throwable $x) { + $e = new FatalThrowableError($x); + } + if (null !== $e) { $event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode()); $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event); - $e = $event->getException(); + if ($e !== $event->getException()) { + $x = $e = $event->getException(); + } $event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode()); $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); - throw $e; + throw $x; } } else { $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 918200d53cfb3..eb04e8a0ad0ce 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -949,6 +949,62 @@ public function testRunDispatchesAllEventsWithException() $this->assertContains('before.foo.caught.after.', $tester->getDisplay()); } + /** + * @expectedException \LogicException + * @expectedExceptionMessage caught + */ + public function testRunWithErrorAndDispatcher() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + + $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dym.'); + + throw new \Error('dymerr'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'dym')); + $this->assertContains('before.dym.caught.after.', $tester->getDisplay(), 'The PHP Error did not dispached events'); + } + + public function testRunDispatchesAllEventsWithError() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + + $application->register('dym')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dym.'); + + throw new \Error('dymerr'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'dym')); + $this->assertContains('before.dym.caught.after.', $tester->getDisplay(), 'The PHP Error did not dispached events'); + } + + public function testRunWithErrorFailingStatusCode() + { + $application = new Application(); + $application->setDispatcher($this->getDispatcher()); + $application->setAutoExit(false); + + $application->register('dus')->setCode(function (InputInterface $input, OutputInterface $output) { + $output->write('dus.'); + + throw new \Error('duserr'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'dus')); + $this->assertSame(1, $tester->getStatusCode(), 'Status code should be 1'); + } + public function testRunWithDispatcherSkippingCommand() { $application = new Application(); diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index b68129ddfc7e5..1bd4af63cb06e 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=5.3.9" + "php": ">=5.3.9", + "symfony/debug": "~2.7,>=2.7.2" }, "require-dev": { "symfony/event-dispatcher": "~2.1", From 7806e2a05da3228480b34b2aa867b36235f0c9e3 Mon Sep 17 00:00:00 2001 From: HeahDude Date: Sun, 11 Sep 2016 01:56:49 +0200 Subject: [PATCH 05/43] Fixed collapsed ChoiceType options attributes --- .../Resources/views/Form/choice_attributes.html.php | 1 - src/Symfony/Component/Form/Tests/AbstractLayoutTest.php | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_attributes.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_attributes.html.php index 8d2d6d7fd63c3..18f8368dc8065 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_attributes.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_attributes.html.php @@ -1,4 +1,3 @@ -id="escape($id) ?>" name="escape($full_name) ?>" disabled="disabled" $v): ?> diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 01b3d3757a597..6441c07f6bf39 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -612,8 +612,8 @@ public function testSingleChoiceAttributesWithMainAttributes() [@class="bar&baz"] [not(@required)] [ - ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"] - /following-sibling::option[@value="&b"][not(@class)][not(@selected)][.="[trans]Choice&B[/trans]"] + ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"][not(@id)][not(@name)] + /following-sibling::option[@value="&b"][not(@class)][not(@selected)][.="[trans]Choice&B[/trans]"][not(@id)][not(@name)] ] [count(./option)=2] ' From 9eb8524d184d575a052d4850db61e59125cc2b59 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 12 Sep 2016 12:06:58 +0200 Subject: [PATCH 06/43] [travis/appveyor] Wire simple-phpunit --- .github/build-packages.php | 74 +++++++++++++ .github/travis.php | 54 ---------- .travis.yml | 17 +-- appveyor.yml | 10 +- composer.json | 6 +- phpunit | 213 +------------------------------------ 6 files changed, 97 insertions(+), 277 deletions(-) create mode 100644 .github/build-packages.php delete mode 100644 .github/travis.php diff --git a/.github/build-packages.php b/.github/build-packages.php new file mode 100644 index 0000000000000..2a2b4a396c07f --- /dev/null +++ b/.github/build-packages.php @@ -0,0 +1,74 @@ + $_SERVER['argc']) { + echo "Usage: branch version dir1 dir2 ... dirN\n"; + exit(1); +} +chdir(dirname(__DIR__)); + +$dirs = $_SERVER['argv']; +array_shift($dirs); +$mergeBase = trim(shell_exec(sprintf('git merge-base %s HEAD', array_shift($dirs)))); +$version = array_shift($dirs); + +$packages = array(); +$flags = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE : 0; + +foreach ($dirs as $k => $dir) { + if (!system("git diff --name-only $mergeBase -- $dir", $exitStatus)) { + if ($exitStatus) { + exit($exitStatus); + } + unset($dirs[$k]); + continue; + } + echo "$dir\n"; + + $json = ltrim(file_get_contents($dir.'/composer.json')); + if (null === $package = json_decode($json)) { + passthru("composer validate $dir/composer.json"); + exit(1); + } + + $package->repositories = array(array( + 'type' => 'composer', + 'url' => 'file://'.str_replace(DIRECTORY_SEPARATOR, '/', dirname(__DIR__)).'/', + )); + if (false === strpos($json, "\n \"repositories\": [\n")) { + $json = rtrim(json_encode(array('repositories' => $package->repositories), $flags), "\n}").','.substr($json, 1); + file_put_contents($dir.'/composer.json', $json); + } + passthru("cd $dir && tar -cf package.tar --exclude='package.tar' *"); + + $package->version = $version.'.999'; + $package->dist['type'] = 'tar'; + $package->dist['url'] = 'file://'.str_replace(DIRECTORY_SEPARATOR, '/', dirname(__DIR__))."/$dir/package.tar"; + + $packages[$package->name][$package->version] = $package; + + $versions = file_get_contents('https://packagist.org/packages/'.$package->name.'.json'); + $versions = json_decode($versions); + + foreach ($versions->package->versions as $v => $package) { + $packages[$package->name] += array($v => $package); + } +} + +file_put_contents('packages.json', json_encode(compact('packages'), $flags)); + +if ($dirs) { + $json = ltrim(file_get_contents('composer.json')); + if (null === $package = json_decode($json)) { + passthru("composer validate $dir/composer.json"); + exit(1); + } + + $package->repositories = array(array( + 'type' => 'composer', + 'url' => 'file://'.str_replace(DIRECTORY_SEPARATOR, '/', dirname(__DIR__)).'/', + )); + if (false === strpos($json, "\n \"repositories\": [\n")) { + $json = rtrim(json_encode(array('repositories' => $package->repositories), $flags), "\n}").','.substr($json, 1); + file_put_contents('composer.json', $json); + } +} diff --git a/.github/travis.php b/.github/travis.php deleted file mode 100644 index 695c69604fe67..0000000000000 --- a/.github/travis.php +++ /dev/null @@ -1,54 +0,0 @@ - $_SERVER['argc']) { - echo "Usage: branch version dir1 dir2 ... dirN\n"; - exit(1); -} -chdir(dirname(__DIR__)); - -$dirs = $_SERVER['argv']; -array_shift($dirs); -$branch = array_shift($dirs); -$version = array_shift($dirs); - -$packages = array(); -$flags = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE : 0; - -foreach ($dirs as $dir) { - if (!system("git diff --name-only $branch...HEAD -- $dir", $exitStatus)) { - if ($exitStatus) { - exit($exitStatus); - } - continue; - } - echo "$dir\n"; - - $json = ltrim(file_get_contents($dir.'/composer.json')); - if (null === $package = json_decode($json)) { - passthru("composer validate $dir/composer.json"); - exit(1); - } - - $package->repositories = array(array( - 'type' => 'composer', - 'url' => 'file://'.dirname(__DIR__).'/', - )); - $json = rtrim(json_encode(array('repositories' => $package->repositories), $flags), "\n}").','.substr($json, 1); - file_put_contents($dir.'/composer.json', $json); - passthru("cd $dir && tar -cf package.tar --exclude='package.tar' *"); - - $package->version = $version.'.999'; - $package->dist['type'] = 'tar'; - $package->dist['url'] = 'file://'.dirname(__DIR__)."/$dir/package.tar"; - - $packages[$package->name][$package->version] = $package; - - $versions = file_get_contents('https://packagist.org/packages/'.$package->name.'.json'); - $versions = json_decode($versions); - - foreach ($versions->package->versions as $v => $package) { - $packages[$package->name] += array($v => $package); - } -} - -file_put_contents('packages.json', json_encode(compact('packages'), $flags)); diff --git a/.travis.yml b/.travis.yml index f7fbaa300cf8b..57e639da8592d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,22 +58,27 @@ before_install: - if [[ ! $skip && ! $PHP = hhvm* ]]; then echo extension = ldap.so >> $INI_FILE; fi - if [[ ! $skip && ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi - if [[ ! $skip ]]; then [ -d ~/.composer ] || mkdir ~/.composer; cp .composer/* ~/.composer/; fi - - if [[ ! $skip ]]; then ./phpunit install; fi - if [[ ! $skip ]]; then export PHPUNIT=$(readlink -f ./phpunit); fi install: + - if [[ ! $skip && $deps ]]; then cp composer.json composer.json.orig; fi + - if [[ ! $skip && $deps ]]; then echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json; 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 [[ ! $skip && $deps ]]; then git fetch origin $TRAVIS_BRANCH && php .github/travis.php FETCH_HEAD $TRAVIS_BRANCH $COMPONENTS; fi + - if [[ ! $skip && $deps ]]; then php .github/build-packages.php HEAD^ $TRAVIS_BRANCH $COMPONENTS; fi + - if [[ ! $skip && $deps ]]; then mv composer.json composer.json.phpunit; mv composer.json.orig composer.json; fi + - if [[ ! $skip && ! $deps ]]; then php .github/build-packages.php HEAD^ $TRAVIS_BRANCH src/Symfony/Bridge/PhpUnit; 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 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'); 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 [[ ! $PHP = hhvm* ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi + - if [[ ! $skip && $deps ]]; then export SYMFONY_DEPRECATIONS_HELPER=weak; fi + - if [[ ! $skip && $deps ]]; then mv composer.json.phpunit composer.json; fi + - if [[ ! $skip ]]; then composer update; fi + - if [[ ! $skip ]]; then COMPOSER_ROOT_VERSION= ./phpunit install; fi + - if [[ ! $skip && ! $PHP = hhvm* ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; fi script: - if [[ $skip ]]; then echo -e "\\n\\e[1;34mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"; fi diff --git a/appveyor.yml b/appveyor.yml index 6e143bf4aba94..768c52416d138 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -48,18 +48,20 @@ install: - echo curl.cainfo=c:\php\cacert.pem >> php.ini-max - copy /Y php.ini-max php.ini - cd c:\projects\symfony - - IF NOT EXIST composer.phar (appveyor DownloadFile https://getcomposer.org/download/1.2.0/composer.phar) + - IF NOT EXIST composer.phar (appveyor DownloadFile https://getcomposer.org/download/1.2.1/composer.phar) - php composer.phar self-update - copy /Y .composer\* %APPDATA%\Composer\ - - php phpunit install + - php .github/build-packages.php "HEAD^" %APPVEYOR_REPO_BRANCH% src\Symfony\Bridge\PhpUnit - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) - php composer.phar update --no-progress --ansi + - SET COMPOSER_ROOT_VERSION= + - php phpunit install test_script: - cd c:\projects\symfony - SET X=0 - copy /Y c:\php\php.ini-min c:\php\php.ini - - php phpunit symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! + - php phpunit src\Symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! - copy /Y c:\php\php.ini-max c:\php\php.ini - - php phpunit symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! + - php phpunit src\Symfony --exclude-group benchmark,intl-data || SET X=!errorlevel! - exit %X% diff --git a/composer.json b/composer.json index 613e53f5aa35e..05e9d158aef31 100644 --- a/composer.json +++ b/composer.json @@ -78,6 +78,7 @@ "monolog/monolog": "~1.11", "ircmaxell/password-compat": "~1.0", "ocramius/proxy-manager": "~0.4|~1.0|~2.0", + "symfony/phpunit-bridge": "~3.2", "egulias/email-validator": "~1.2,>=1.2.1" }, "autoload": { @@ -99,11 +100,6 @@ "**/Tests/" ] }, - "autoload-dev": { - "psr-4": { - "Symfony\\Bridge\\PhpUnit\\": "src/Symfony/Bridge/PhpUnit/" - } - }, "minimum-stability": "dev", "extra": { "branch-alias": { diff --git a/phpunit b/phpunit index 22432a093c267..f9243bcbf9e79 100755 --- a/phpunit +++ b/phpunit @@ -1,212 +1,9 @@ #!/usr/bin/env php - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -// Please update when phpunit needs to be reinstalled with fresh deps: -// Cache-Id-Version: 2016-06-29 13:45 UTC - -use Symfony\Component\Process\ProcessUtils; - -error_reporting(-1); -require __DIR__.'/src/Symfony/Component/Process/ProcessUtils.php'; - -// PHPUnit 4.8 does not support PHP 7, while 5.1 requires PHP 5.6+ -$PHPUNIT_VERSION = PHP_VERSION_ID >= 50600 ? '5.1' : '4.8'; -$PHPUNIT_DIR = __DIR__.'/.phpunit'; -$PHP = defined('PHP_BINARY') ? PHP_BINARY : 'php'; -$PHP = ProcessUtils::escapeArgument($PHP); -if ('phpdbg' === PHP_SAPI) { - $PHP .= ' -qrr'; -} - -$COMPOSER = file_exists($COMPOSER = __DIR__.'/composer.phar') || ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar`)) - ? $PHP.' '.ProcessUtils::escapeArgument($COMPOSER) - : 'composer'; - -if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__FILE__) !== @file_get_contents("$PHPUNIT_DIR/.$PHPUNIT_VERSION.md5")) { - // Build a standalone phpunit without symfony/yaml - - $oldPwd = getcwd(); - @mkdir($PHPUNIT_DIR); - chdir($PHPUNIT_DIR); - if (file_exists("phpunit-$PHPUNIT_VERSION")) { - passthru(sprintf('\\' === DIRECTORY_SEPARATOR ? '(del /S /F /Q %s & rmdir %1$s) >nul': 'rm -rf %s', "phpunit-$PHPUNIT_VERSION")); - } - if (extension_loaded('openssl') && ini_get('allow_url_fopen')) { - stream_copy_to_stream(fopen("https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip", 'rb'), fopen("$PHPUNIT_VERSION.zip", 'wb')); - } else { - @unlink("$PHPUNIT_VERSION.zip"); - passthru("wget https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip"); - } - $zip = new ZipArchive(); - $zip->open("$PHPUNIT_VERSION.zip"); - $zip->extractTo(getcwd()); - $zip->close(); - chdir("phpunit-$PHPUNIT_VERSION"); - passthru("$COMPOSER remove --no-update phpspec/prophecy"); - passthru("$COMPOSER remove --no-update symfony/yaml"); - if (5.1 <= $PHPUNIT_VERSION && $PHPUNIT_VERSION < 5.4) { - passthru("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); - } - passthru("$COMPOSER require --dev --no-update symfony/phpunit-bridge \">=3.2@dev\""); - passthru("$COMPOSER install --prefer-dist --no-progress --ansi", $exit); - if ($exit) { - exit($exit); - } - file_put_contents('phpunit', <<<'EOPHP' -addPsr4('Symfony\\Bridge\\PhpUnit\\', array('src/Symfony/Bridge/PhpUnit'), true); -} -unset($loader); -Symfony\Bridge\PhpUnit\TextUI\Command::main(); - -EOPHP - ); - chdir('..'); - file_put_contents(".$PHPUNIT_VERSION.md5", md5_file(__FILE__)); - chdir($oldPwd); - -} - -$cmd = array_map('Symfony\Component\Process\ProcessUtils::escapeArgument', $argv); -$exit = 0; - -if (isset($argv[1]) && 'symfony' === $argv[1]) { - array_shift($cmd); -} - -$cmd[0] = sprintf('%s %s --colors=always', $PHP, ProcessUtils::escapeArgument("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit")); -$cmd = str_replace('%', '%%', implode(' ', $cmd)).' %1$s'; - -if ('\\' === DIRECTORY_SEPARATOR) { - $cmd = 'cmd /v:on /d /c "('.$cmd.')%2$s"'; -} else { - $cmd .= '%2$s'; -} - -if (isset($argv[1]) && 'symfony' === $argv[1]) { - // Find Symfony components in plain php for Windows portability - - $oldPwd = getcwd(); - chdir(__DIR__); - $finder = new RecursiveDirectoryIterator('src/Symfony', FilesystemIterator::KEY_AS_FILENAME | FilesystemIterator::UNIX_PATHS); - $finder = new RecursiveIteratorIterator($finder); - $finder->setMaxDepth(3); - - $skippedTests = isset($_SERVER['SYMFONY_PHPUNIT_SKIPPED_TESTS']) ? $_SERVER['SYMFONY_PHPUNIT_SKIPPED_TESTS'] : false; - $runningProcs = array(); - - foreach ($finder as $file => $fileInfo) { - if ('phpunit.xml.dist' === $file) { - $component = dirname($fileInfo->getPathname()); - - // Run phpunit tests in parallel - - if ($skippedTests) { - putenv("SYMFONY_PHPUNIT_SKIPPED_TESTS=$component/$skippedTests"); - } - - $c = ProcessUtils::escapeArgument($component); - - if ($proc = proc_open(sprintf($cmd, $c, " > $c/phpunit.stdout 2> $c/phpunit.stderr"), array(), $pipes)) { - $runningProcs[$component] = $proc; - } else { - $exit = 1; - echo "\033[41mKO\033[0m $component\n\n"; - } - } - } - chdir($oldPwd); - - // Fixes for colors support on appveyor - // See https://github.com/appveyor/ci/issues/373 - $colorFixes = array( - array("S\033[0m\033[0m\033[36m\033[1mS", "E\033[0m\033[0m\033[31m\033[1mE", "I\033[0m\033[0m\033[33m\033[1mI", "F\033[0m\033[0m\033[41m\033[37mF"), - array("SS", "EE", "II", "FF"), - ); - $colorFixes[0] = array_merge($colorFixes[0], $colorFixes[0]); - $colorFixes[1] = array_merge($colorFixes[1], $colorFixes[1]); - - while ($runningProcs) { - usleep(300000); - $terminatedProcs = array(); - foreach ($runningProcs as $component => $proc) { - $procStatus = proc_get_status($proc); - if (!$procStatus['running']) { - $terminatedProcs[$component] = $procStatus['exitcode']; - unset($runningProcs[$component]); - proc_close($proc); - } - } - - foreach ($terminatedProcs as $component => $procStatus) { - foreach (array('out', 'err') as $file) { - $file = "$component/phpunit.std$file"; - - if ('\\' === DIRECTORY_SEPARATOR) { - $h = fopen($file, 'rb'); - while (false !== $line = fgets($h)) { - echo str_replace($colorFixes[0], $colorFixes[1], preg_replace( - '/(\033\[[0-9]++);([0-9]++m)(?:(.)(\033\[0m))?/', - "$1m\033[$2$3$4$4", - $line - )); - } - fclose($h); - } else { - readfile($file); - } - unlink($file); - } - - // Fail on any individual component failures but ignore some error codes on Windows when APCu is enabled: - // STATUS_STACK_BUFFER_OVERRUN (-1073740791/0xC0000409) - // STATUS_ACCESS_VIOLATION (-1073741819/0xC0000005) - // STATUS_HEAP_CORRUPTION (-1073740940/0xC0000374) - if ($procStatus && ('\\' !== DIRECTORY_SEPARATOR || !extension_loaded('apcu') || !ini_get('apc.enable_cli') || !in_array($procStatus, array(-1073740791, -1073741819, -1073740940)))) { - $exit = $procStatus; - echo "\033[41mKO\033[0m $component\n\n"; - } else { - echo "\033[32mOK\033[0m $component\n\n"; - } - } - } -} elseif (!isset($argv[1]) || 'install' !== $argv[1]) { - // Run regular phpunit in a subprocess - - $errFile = tempnam(sys_get_temp_dir(), 'phpunit.stderr.'); - if ($proc = proc_open(sprintf($cmd, '', ' 2> '.ProcessUtils::escapeArgument($errFile)), array(1 => array('pipe', 'w')), $pipes)) { - stream_copy_to_stream($pipes[1], STDOUT); - fclose($pipes[1]); - $exit = proc_close($proc); - - readfile($errFile); - unlink($errFile); - } - - if (!file_exists($component = array_pop($argv))) { - $component = basename(getcwd()); - } - - if ($exit) { - echo "\033[41mKO\033[0m $component\n\n"; - } else { - echo "\033[32mOK\033[0m $component\n\n"; - } +if (!file_exists(__DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit')) { + echo "Unable to find the `simple-phpunit` script in `vendor/symfony/phpunit-bridge/bin/`.\nPlease run `composer update` before running this command.\n"; + exit(1); } - -exit($exit); +putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit'); +require __DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit'; From 04275945efe1f0d035f1744543138804e3826c3e Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Mon, 12 Sep 2016 23:15:58 +0200 Subject: [PATCH 07/43] Use JSON_UNESCAPED_SLASHES for lint commands output --- src/Symfony/Bridge/Twig/Command/LintCommand.php | 2 +- src/Symfony/Bundle/FrameworkBundle/Command/YamlLintCommand.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Command/LintCommand.php b/src/Symfony/Bridge/Twig/Command/LintCommand.php index 95d550a058bc3..42287a15717a5 100644 --- a/src/Symfony/Bridge/Twig/Command/LintCommand.php +++ b/src/Symfony/Bridge/Twig/Command/LintCommand.php @@ -202,7 +202,7 @@ private function displayJson(OutputInterface $output, $filesInfo) } }); - $output->writeln(json_encode($filesInfo, defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0)); + $output->writeln(json_encode($filesInfo, defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES : 0)); return min($errors, 1); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/YamlLintCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/YamlLintCommand.php index 4c12e7d2fca05..b41f5f3479ebe 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/YamlLintCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/YamlLintCommand.php @@ -156,7 +156,7 @@ private function displayJson(OutputInterface $output, $filesInfo) } }); - $output->writeln(json_encode($filesInfo, defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0)); + $output->writeln(json_encode($filesInfo, defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES : 0)); return min($errors, 1); } From 4214311a1cf7a076fff999e832a772b96463377f Mon Sep 17 00:00:00 2001 From: Javier Spagnoletti Date: Mon, 12 Sep 2016 23:49:02 -0300 Subject: [PATCH 08/43] [bugfix] [Console] Set `Input::$interactive` to `false` when command is executed with `--quiet` as verbosity level --- src/Symfony/Component/Console/Application.php | 3 ++- src/Symfony/Component/Console/Tests/ApplicationTest.php | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index c2c13b8aedbd4..b11268ade33bf 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -337,7 +337,7 @@ public function register($name) * Adds an array of command objects. * * If a Command is not enabled it will not be added. - * + * * @param Command[] $commands An array of commands */ public function addCommands(array $commands) @@ -808,6 +808,7 @@ protected function configureIO(InputInterface $input, OutputInterface $output) if (true === $input->hasParameterOption(array('--quiet', '-q'))) { $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + $input->setInteractive(false); } else { if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) { $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index eb04e8a0ad0ce..9d375f6b7b264 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -636,9 +636,11 @@ public function testRun() $tester->run(array('command' => 'list', '--quiet' => true)); $this->assertSame('', $tester->getDisplay(), '->run() removes all output if --quiet is passed'); + $this->assertFalse($tester->getInput()->isInteractive(), '->run() sets off the interactive mode if --quiet is passed'); $tester->run(array('command' => 'list', '-q' => true)); $this->assertSame('', $tester->getDisplay(), '->run() removes all output if -q is passed'); + $this->assertFalse($tester->getInput()->isInteractive(), '->run() sets off the interactive mode if -q is passed'); $tester->run(array('command' => 'list', '--verbose' => true)); $this->assertSame(Output::VERBOSITY_VERBOSE, $tester->getOutput()->getVerbosity(), '->run() sets the output to verbose if --verbose is passed'); From 86a151c9f57adc3cb3734aa7b74d5bf1462bf0ce Mon Sep 17 00:00:00 2001 From: Jakub Zalas Date: Tue, 13 Sep 2016 12:11:56 +0100 Subject: [PATCH 09/43] [Validator] Update IpValidatorTest data set with a valid reserved IP The validator uses PHP filter which was recently fixed (see https://bugs.php.net/bug.php?id=72972). --- .../Component/Validator/Tests/Constraints/IpValidatorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php index fc40e6104e14b..2c5dea549b71f 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IpValidatorTest.php @@ -218,7 +218,7 @@ public function getInvalidReservedIpsV4() { return array( array('0.0.0.0'), - array('224.0.0.1'), + array('240.0.0.1'), array('255.255.255.255'), ); } From 221e21cf40eea80781d47b6efc527742e870e613 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 13 Sep 2016 13:35:02 +0200 Subject: [PATCH 10/43] [ci] Fix build-packages.php --- .github/build-packages.php | 11 +++++++---- .travis.yml | 4 ++-- appveyor.yml | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/build-packages.php b/.github/build-packages.php index 2a2b4a396c07f..ec629998f600d 100644 --- a/.github/build-packages.php +++ b/.github/build-packages.php @@ -1,7 +1,7 @@ $_SERVER['argc']) { - echo "Usage: branch version dir1 dir2 ... dirN\n"; +if (3 > $_SERVER['argc']) { + echo "Usage: branch dir1 dir2 ... dirN\n"; exit(1); } chdir(dirname(__DIR__)); @@ -9,7 +9,6 @@ $dirs = $_SERVER['argv']; array_shift($dirs); $mergeBase = trim(shell_exec(sprintf('git merge-base %s HEAD', array_shift($dirs)))); -$version = array_shift($dirs); $packages = array(); $flags = PHP_VERSION_ID >= 50400 ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE : 0; @@ -40,7 +39,11 @@ } passthru("cd $dir && tar -cf package.tar --exclude='package.tar' *"); - $package->version = $version.'.999'; + if (!isset($package->extra->{'branch-alias'}->{'dev-master'})) { + echo "Missing \"dev-master\" branch-alias in composer.json extra.\n"; + exit(1); + } + $package->version = str_replace('-dev', '.999', $package->extra->{'branch-alias'}->{'dev-master'}); $package->dist['type'] = 'tar'; $package->dist['url'] = 'file://'.str_replace(DIRECTORY_SEPARATOR, '/', dirname(__DIR__))."/$dir/package.tar"; diff --git a/.travis.yml b/.travis.yml index 57e639da8592d..bbf7547445fb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -65,9 +65,9 @@ install: - if [[ ! $skip && $deps ]]; then echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json; 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 [[ ! $skip && $deps ]]; then php .github/build-packages.php HEAD^ $TRAVIS_BRANCH $COMPONENTS; fi + - if [[ ! $skip && $deps ]]; then php .github/build-packages.php HEAD^ $COMPONENTS; fi - if [[ ! $skip && $deps ]]; then mv composer.json composer.json.phpunit; mv composer.json.orig composer.json; fi - - if [[ ! $skip && ! $deps ]]; then php .github/build-packages.php HEAD^ $TRAVIS_BRANCH src/Symfony/Bridge/PhpUnit; fi + - if [[ ! $skip && ! $deps ]]; then php .github/build-packages.php HEAD^ src/Symfony/Bridge/PhpUnit; 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'); fi diff --git a/appveyor.yml b/appveyor.yml index 768c52416d138..adf63a1539493 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -51,7 +51,7 @@ install: - IF NOT EXIST composer.phar (appveyor DownloadFile https://getcomposer.org/download/1.2.1/composer.phar) - php composer.phar self-update - copy /Y .composer\* %APPDATA%\Composer\ - - php .github/build-packages.php "HEAD^" %APPVEYOR_REPO_BRANCH% src\Symfony\Bridge\PhpUnit + - php .github/build-packages.php "HEAD^" src\Symfony\Bridge\PhpUnit - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) - php composer.phar update --no-progress --ansi - SET COMPOSER_ROOT_VERSION= From e8708195e2b50180dce085f15bec65ccabea7cfe Mon Sep 17 00:00:00 2001 From: Tristan Darricau Date: Sun, 11 Sep 2016 15:39:04 +0200 Subject: [PATCH 11/43] [Config] Handle open_basedir restrictions in FileLocator Silence `file_exists()` call to avoid open_basedir restrictions warning. (can happen when using relative imports) --- src/Symfony/Component/Config/FileLocator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Config/FileLocator.php b/src/Symfony/Component/Config/FileLocator.php index c6600c7783760..4816724c8190e 100644 --- a/src/Symfony/Component/Config/FileLocator.php +++ b/src/Symfony/Component/Config/FileLocator.php @@ -57,7 +57,7 @@ public function locate($name, $currentPath = null, $first = true) $filepaths = array(); foreach ($paths as $path) { - if (file_exists($file = $path.DIRECTORY_SEPARATOR.$name)) { + if (@file_exists($file = $path.DIRECTORY_SEPARATOR.$name)) { if (true === $first) { return $file; } From 82415a1667462d9e4cabfa6858e7fcda2a86e45a Mon Sep 17 00:00:00 2001 From: Fabien Bourigault Date: Wed, 14 Sep 2016 09:33:27 +0200 Subject: [PATCH 12/43] [Form] Fix typo in doc comment --- src/Symfony/Component/Form/PreloadedExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/PreloadedExtension.php b/src/Symfony/Component/Form/PreloadedExtension.php index 65519f83d493e..871e8b3791bc9 100644 --- a/src/Symfony/Component/Form/PreloadedExtension.php +++ b/src/Symfony/Component/Form/PreloadedExtension.php @@ -14,7 +14,7 @@ use Symfony\Component\Form\Exception\InvalidArgumentException; /** - * A form extension with preloaded types, type exceptions and type guessers. + * A form extension with preloaded types, type extensions and type guessers. * * @author Bernhard Schussek */ From 81e9713c80eae37c3b98b7ea4b2dc34635b05aa5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 14 Sep 2016 13:34:59 -0700 Subject: [PATCH 13/43] fixed CS --- src/Symfony/Bridge/Twig/Command/LintCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Command/LintCommand.php b/src/Symfony/Bridge/Twig/Command/LintCommand.php index 42287a15717a5..4d8b9ce1691fb 100644 --- a/src/Symfony/Bridge/Twig/Command/LintCommand.php +++ b/src/Symfony/Bridge/Twig/Command/LintCommand.php @@ -202,7 +202,7 @@ private function displayJson(OutputInterface $output, $filesInfo) } }); - $output->writeln(json_encode($filesInfo, defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES : 0)); + $output->writeln(json_encode($filesInfo, defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES : 0)); return min($errors, 1); } From 695e3412587b5a876f8b05f9b74b98ca958a8b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Go=CC=88tz=20Gottwald?= Date: Tue, 16 Aug 2016 16:22:05 +0200 Subject: [PATCH 14/43] [Finder] no PHP warning on empty directory iteration --- .../Component/Finder/Iterator/RecursiveDirectoryIterator.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php index 402033a5c2816..f011ce8d4d921 100644 --- a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php +++ b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php @@ -137,6 +137,10 @@ public function isRewindable() return $this->rewindable; } + if ('' === $this->getPath()) { + return $this->rewindable = false; + } + if (false !== $stream = @opendir($this->getPath())) { $infos = stream_get_meta_data($stream); closedir($stream); From b28cd815753b40585657e3d0af9dace8e52eba78 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 14 Sep 2016 14:04:40 -0700 Subject: [PATCH 15/43] added a comment about a workaround --- .../Component/Finder/Iterator/RecursiveDirectoryIterator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php index f011ce8d4d921..1df2f5014f622 100644 --- a/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php +++ b/src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php @@ -137,6 +137,7 @@ public function isRewindable() return $this->rewindable; } + // workaround for an HHVM bug, should be removed when https://github.com/facebook/hhvm/issues/7281 is fixed if ('' === $this->getPath()) { return $this->rewindable = false; } From e0e5f0c3795399528b8232f189f42c80f00f1144 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sat, 13 Aug 2016 10:02:45 +0000 Subject: [PATCH 16/43] apply rtrim --- .../Iterator/ExcludeDirectoryFilterIterator.php | 3 ++- .../ExcludeDirectoryFilterIteratorTest.php | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php index b7bb3c4f31310..3f5a5dfeb133c 100644 --- a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -35,6 +35,7 @@ public function __construct(\Iterator $iterator, array $directories) $this->isRecursive = $iterator instanceof \RecursiveIterator; $patterns = array(); foreach ($directories as $directory) { + $directory = rtrim($directory, '/'); if (!$this->isRecursive || false !== strpos($directory, '/')) { $patterns[] = preg_quote($directory, '#'); } else { @@ -51,7 +52,7 @@ public function __construct(\Iterator $iterator, array $directories) /** * Filters the iterator values. * - * @return bool true if the value should be kept, false otherwise + * @return bool True if the value should be kept, false otherwise */ public function accept() { diff --git a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php index c5f4ba495a7ca..fa192c31f4dec 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php @@ -58,9 +58,23 @@ public function getAcceptData() 'foo bar', ); + $toto = array( + '.bar', + '.foo', + '.foo/.bar', + '.foo/bar', + '.git', + 'test.py', + 'foo', + 'foo/bar.tmp', + 'test.php', + 'foo bar', + ); + return array( array(array('foo'), $this->toAbsolute($foo)), array(array('fo'), $this->toAbsolute($fo)), + array(array('toto/'), $this->toAbsolute($toto)), ); } } From 8952155f9249473d49ce8d14aef8a8fcc1d90e47 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 15 Sep 2016 22:28:04 +0200 Subject: [PATCH 17/43] [Console] Fix empty optionnal options with = separator in argv --- .../Component/Console/Input/ArgvInput.php | 7 +++- .../Console/Tests/Input/ArgvInputTest.php | 38 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php index f18d6e189970c..119be49170853 100644 --- a/src/Symfony/Component/Console/Input/ArgvInput.php +++ b/src/Symfony/Component/Console/Input/ArgvInput.php @@ -145,7 +145,10 @@ private function parseLongOption($token) $name = substr($token, 2); if (false !== $pos = strpos($name, '=')) { - $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1)); + if (0 === strlen($value = substr($name, $pos + 1))) { + array_unshift($this->parsed, null); + } + $this->addLongOption(substr($name, 0, $pos), $value); } else { $this->addLongOption($name, null); } @@ -232,7 +235,7 @@ private function addLongOption($name, $value) if (isset($next[0]) && '-' !== $next[0]) { $value = $next; } elseif (empty($next)) { - $value = ''; + $value = null; } else { array_unshift($this->parsed, $next); } diff --git a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php index 3b0dc3f231659..06347c87ba807 100644 --- a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php +++ b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php @@ -71,6 +71,18 @@ public function provideOptions() array('foo' => 'bar'), '->parse() parses long options with a required value (with a space separator)', ), + array( + array('cli.php', '--foo='), + array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)), + array('foo' => null), + '->parse() parses long options with optional value which is empty (with a = separator) as null', + ), + array( + array('cli.php', '--foo=', 'bar'), + array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('name', InputArgument::REQUIRED)), + array('foo' => null), + '->parse() parses long options with optional value which is empty (with a = separator) followed by an argument', + ), array( array('cli.php', '-f'), array(new InputOption('foo', 'f')), @@ -324,4 +336,30 @@ public function testParseSingleDashAsArgument() $input->bind(new InputDefinition(array(new InputArgument('file')))); $this->assertEquals(array('file' => '-'), $input->getArguments(), '->parse() parses single dash as an argument'); } + + public function testParseOptionWithValueOptionalGivenEmptyAndRequiredArgument() + { + $input = new ArgvInput(array('cli.php', '--foo=', 'bar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('name', InputArgument::REQUIRED)))); + $this->assertEquals(array('foo' => null), $input->getOptions(), '->parse() parses optional options with empty value as null'); + $this->assertEquals(array('name' => 'bar'), $input->getArguments(), '->parse() parses required arguments'); + + $input = new ArgvInput(array('cli.php', '--foo=0', 'bar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('name', InputArgument::REQUIRED)))); + $this->assertEquals(array('foo' => '0'), $input->getOptions(), '->parse() parses optional options with empty value as null'); + $this->assertEquals(array('name' => 'bar'), $input->getArguments(), '->parse() parses required arguments'); + } + + public function testParseOptionWithValueOptionalGivenEmptyAndOptionalArgument() + { + $input = new ArgvInput(array('cli.php', '--foo=', 'bar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('name', InputArgument::OPTIONAL)))); + $this->assertEquals(array('foo' => null), $input->getOptions(), '->parse() parses optional options with empty value as null'); + $this->assertEquals(array('name' => 'bar'), $input->getArguments(), '->parse() parses optional arguments'); + + $input = new ArgvInput(array('cli.php', '--foo=0', 'bar')); + $input->bind(new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('name', InputArgument::OPTIONAL)))); + $this->assertEquals(array('foo' => '0'), $input->getOptions(), '->parse() parses optional options with empty value as null'); + $this->assertEquals(array('name' => 'bar'), $input->getArguments(), '->parse() parses optional arguments'); + } } From 12350c2eb1e6785edb28b4b938a3c5cc73222711 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 19 Sep 2016 12:59:08 -0700 Subject: [PATCH 18/43] [TwigBridge] removed Twig null nodes (deprecated as of Twig 1.25) --- src/Symfony/Bridge/Twig/Node/DumpNode.php | 13 +++++---- .../Bridge/Twig/Node/StopwatchNode.php | 2 +- src/Symfony/Bridge/Twig/Node/TransNode.php | 29 ++++++++++++++----- .../TranslationDefaultDomainNodeVisitor.php | 2 +- .../NodeVisitor/TranslationNodeVisitor.php | 8 ++--- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Node/DumpNode.php b/src/Symfony/Bridge/Twig/Node/DumpNode.php index 522497ba655dc..a7c152944618f 100644 --- a/src/Symfony/Bridge/Twig/Node/DumpNode.php +++ b/src/Symfony/Bridge/Twig/Node/DumpNode.php @@ -20,7 +20,12 @@ class DumpNode extends \Twig_Node public function __construct($varPrefix, \Twig_Node $values = null, $lineno, $tag = null) { - parent::__construct(array('values' => $values), array(), $lineno, $tag); + $nodes = array(); + if (null !== $values) { + $nodes['values'] = $values; + } + + parent::__construct($nodes, array(), $lineno, $tag); $this->varPrefix = $varPrefix; } @@ -33,9 +38,7 @@ public function compile(\Twig_Compiler $compiler) ->write("if (\$this->env->isDebug()) {\n") ->indent(); - $values = $this->getNode('values'); - - if (null === $values) { + if (!$this->hasNode('values')) { // remove embedded templates (macros) from the context $compiler ->write(sprintf('$%svars = array();'."\n", $this->varPrefix)) @@ -50,7 +53,7 @@ public function compile(\Twig_Compiler $compiler) ->write("}\n") ->addDebugInfo($this) ->write(sprintf('\Symfony\Component\VarDumper\VarDumper::dump($%svars);'."\n", $this->varPrefix)); - } elseif (1 === $values->count()) { + } elseif (($values = $this->getNode('values')) && 1 === $values->count()) { $compiler ->addDebugInfo($this) ->write('\Symfony\Component\VarDumper\VarDumper::dump(') diff --git a/src/Symfony/Bridge/Twig/Node/StopwatchNode.php b/src/Symfony/Bridge/Twig/Node/StopwatchNode.php index 06eeb492728c6..839e3f7698684 100644 --- a/src/Symfony/Bridge/Twig/Node/StopwatchNode.php +++ b/src/Symfony/Bridge/Twig/Node/StopwatchNode.php @@ -18,7 +18,7 @@ */ class StopwatchNode extends \Twig_Node { - public function __construct(\Twig_Node $name, $body, \Twig_Node_Expression_AssignName $var, $lineno = 0, $tag = null) + public function __construct(\Twig_Node $name, \Twig_Node $body, \Twig_Node_Expression_AssignName $var, $lineno = 0, $tag = null) { parent::__construct(array('body' => $body, 'name' => $name, 'var' => $var), array(), $lineno, $tag); } diff --git a/src/Symfony/Bridge/Twig/Node/TransNode.php b/src/Symfony/Bridge/Twig/Node/TransNode.php index af85d8f1858ec..5f1915d05e086 100644 --- a/src/Symfony/Bridge/Twig/Node/TransNode.php +++ b/src/Symfony/Bridge/Twig/Node/TransNode.php @@ -18,7 +18,21 @@ class TransNode extends \Twig_Node { public function __construct(\Twig_Node $body, \Twig_Node $domain = null, \Twig_Node_Expression $count = null, \Twig_Node_Expression $vars = null, \Twig_Node_Expression $locale = null, $lineno = 0, $tag = null) { - parent::__construct(array('count' => $count, 'body' => $body, 'domain' => $domain, 'vars' => $vars, 'locale' => $locale), array(), $lineno, $tag); + $nodes = array('body' => $body); + if (null !== $domain) { + $nodes['domain'] = $domain; + } + if (null !== $count) { + $nodes['count'] = $count; + } + if (null !== $vars) { + $nodes['vars'] = $vars; + } + if (null !== $locale) { + $nodes['locale'] = $locale; + } + + parent::__construct($nodes, array(), $lineno, $tag); } /** @@ -30,15 +44,14 @@ public function compile(\Twig_Compiler $compiler) { $compiler->addDebugInfo($this); - $vars = $this->getNode('vars'); $defaults = new \Twig_Node_Expression_Array(array(), -1); - if ($vars instanceof \Twig_Node_Expression_Array) { + if ($this->hasNode('vars') && ($vars = $this->getNode('vars')) instanceof \Twig_Node_Expression_Array) { $defaults = $this->getNode('vars'); $vars = null; } list($msg, $defaults) = $this->compileString($this->getNode('body'), $defaults, (bool) $vars); - $method = null === $this->getNode('count') ? 'trans' : 'transChoice'; + $method = !$this->hasNode('count') ? 'trans' : 'transChoice'; $compiler ->write('echo $this->env->getExtension(\'translator\')->getTranslator()->'.$method.'(') @@ -47,7 +60,7 @@ public function compile(\Twig_Compiler $compiler) $compiler->raw(', '); - if (null !== $this->getNode('count')) { + if ($this->hasNode('count')) { $compiler ->subcompile($this->getNode('count')) ->raw(', ') @@ -68,13 +81,13 @@ public function compile(\Twig_Compiler $compiler) $compiler->raw(', '); - if (null === $this->getNode('domain')) { + if (!$this->hasNode('domain')) { $compiler->repr('messages'); } else { $compiler->subcompile($this->getNode('domain')); } - if (null !== $this->getNode('locale')) { + if ($this->hasNode('locale')) { $compiler ->raw(', ') ->subcompile($this->getNode('locale')) @@ -98,7 +111,7 @@ protected function compileString(\Twig_Node $body, \Twig_Node_Expression_Array $ foreach ($matches[1] as $var) { $key = new \Twig_Node_Expression_Constant('%'.$var.'%', $body->getLine()); if (!$vars->hasElement($key)) { - if ('count' === $var && null !== $this->getNode('count')) { + if ('count' === $var && $this->hasNode('count')) { $vars->addElement($this->getNode('count'), $key); } else { $varExpr = new \Twig_Node_Expression_Name($var, $body->getLine()); diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php index c923df9944c60..3e850350fd144 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php @@ -78,7 +78,7 @@ protected function doEnterNode(\Twig_Node $node, \Twig_Environment $env) } } } elseif ($node instanceof TransNode) { - if (null === $node->getNode('domain')) { + if (!$node->hasNode('domain')) { $node->setNode('domain', $this->scope->get('domain')); } } diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php index 4426a9d3b6666..6e3880d09ed98 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationNodeVisitor.php @@ -75,7 +75,7 @@ protected function doEnterNode(\Twig_Node $node, \Twig_Environment $env) // extract trans nodes $this->messages[] = array( $node->getNode('body')->getAttribute('data'), - $this->getReadDomainFromNode($node->getNode('domain')), + $node->hasNode('domain') ? $this->getReadDomainFromNode($node->getNode('domain')) : null, ); } @@ -122,12 +122,8 @@ private function getReadDomainFromArguments(\Twig_Node $arguments, $index) * * @return string|null */ - private function getReadDomainFromNode(\Twig_Node $node = null) + private function getReadDomainFromNode(\Twig_Node $node) { - if (null === $node) { - return; - } - if ($node instanceof \Twig_Node_Expression_Constant) { return $node->getAttribute('value'); } From 0d9dacc6db3818bd0a7067d01b68089602c1701b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 20 Sep 2016 14:38:50 +0200 Subject: [PATCH 19/43] [VarDumper] Fix extra whitespace --- .../Tests/DataCollector/DumpDataCollectorTest.php | 8 +++----- src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php index 18824635ea44f..68d28cf2d211a 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php @@ -87,19 +87,17 @@ public function testCollectHtml() $file = __FILE__; if (PHP_VERSION_ID >= 50400) { $xOutput = <<DumpDataCollectorTest.php on line {$line}: +
DumpDataCollectorTest.php on line {$line}:
 123
 
- EOTXT; } else { $len = strlen("DumpDataCollectorTest.php on line {$line}:"); $xOutput = <<"DumpDataCollectorTest.php on line {$line}:" +
"DumpDataCollectorTest.php on line {$line}:"
 
123
 
- EOTXT; } @@ -111,7 +109,7 @@ public function testCollectHtml() $output = preg_replace('#<(script|style).*?#s', '', $output); $output = preg_replace('/sf-dump-\d+/', 'sf-dump', $output); - $this->assertSame($xOutput, $output); + $this->assertSame($xOutput, trim($output)); $this->assertSame(1, $collector->getDumpsCount()); $collector->serialize(); } diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php index 9a47aea7ee296..bd69f2eddf371 100644 --- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php @@ -288,8 +288,7 @@ function isCtrlKey(e) { }; })(document); - -