Merge branch '3.1'

* 3.1:
  [travis/appveyor] Wire simple-phpunit
  [Console] fixed PHP7 Errors are now handled and converted to Exceptions
  Fix #19721
  Fix translation:update command count
  bumped Symfony version to 2.8.12
  updated VERSION for 2.8.11
  updated CHANGELOG for 2.8.11
  bumped Symfony version to 2.7.19
  updated VERSION for 2.7.18
  update CONTRIBUTORS for 2.7.18
  updated CHANGELOG for 2.7.18
  [Security] Optimize RoleHierarchy's buildRoleMap method
  [FrameworkBundle] Fix Incorrect line break in exception message (500 debug page)
  [Security] Added note inside phpdoc.
  Minor cleanups and improvements
  [form] lazy trans `post_max_size_message`.
  [DI] Fix setting synthetic services on ContainerBuilder
  [ClassLoader] Fix ClassCollectionLoader inlining with declare(strict_types=1)
This commit is contained in:
Nicolas Grekas 2016-09-12 21:03:45 +02:00
commit f5c1b1c077
36 changed files with 343 additions and 144 deletions

74
.github/build-packages.php vendored Normal file
View File

@ -0,0 +1,74 @@
<?php
if (4 > $_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);
}
}

54
.github/travis.php vendored
View File

@ -1,54 +0,0 @@
<?php
if (4 > $_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 = 'master' !== $version ? $version.'.999' : 'dev-master';
$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') ?: '{"package":{"versions":[]}}';
$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));

View File

@ -64,24 +64,29 @@ before_install:
- if [[ ! $skip && ! $PHP = hhvm* ]]; then echo extension = redis.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
- if [[ ! $skip ]]; then ldapadd -h localhost:3389 -D cn=admin,dc=symfony,dc=com -w symfony -f src/Symfony/Component/Ldap/Tests/Fixtures/data/base.ldif; fi
- if [[ ! $skip ]]; then ldapadd -h localhost:3389 -D cn=admin,dc=symfony,dc=com -w symfony -f src/Symfony/Component/Ldap/Tests/Fixtures/data/fixtures.ldif; 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

View File

@ -16,8 +16,8 @@ Symfony is the result of the work of many people who made the code better
- Kris Wallsmith (kriswallsmith)
- Jakub Zalas (jakubzalas)
- Ryan Weaver (weaverryan)
- Kévin Dunglas (dunglas)
- Javier Eguiluz (javier.eguiluz)
- Kévin Dunglas (dunglas)
- Hugo Hamon (hhamon)
- Abdellatif Ait boudad (aitboudad)
- Pascal Borreli (pborreli)
@ -52,8 +52,8 @@ Symfony is the result of the work of many people who made the code better
- Konstantin Kudryashov (everzet)
- Bilal Amarni (bamarni)
- Florin Patan (florinpatan)
- Peter Rehm (rpet)
- Ener-Getick (energetick)
- Peter Rehm (rpet)
- Iltar van der Berg (kjarli)
- Kevin Bond (kbond)
- Andrej Hudec (pulzarraider)
@ -315,6 +315,7 @@ Symfony is the result of the work of many people who made the code better
- JhonnyL
- hossein zolfi (ocean)
- Clément Gautier (clementgautier)
- James Halsall (jaitsu)
- Eduardo Gulias (egulias)
- giulio de donato (liuggio)
- Stéphane PY (steph_py)
@ -396,7 +397,6 @@ Symfony is the result of the work of many people who made the code better
- Christian Wahler
- Mathieu Lemoine
- Gintautas Miselis
- James Halsall (jaitsu)
- David Badura (davidbadura)
- Zander Baldwin
- Adam Harvey
@ -1302,6 +1302,7 @@ Symfony is the result of the work of many people who made the code better
- Muriel (metalmumu)
- Michael Pohlers (mick_the_big)
- Cayetano Soriano Gallego (neoshadybeat)
- Ondrej Machulda (ondram)
- Patrick McDougle (patrick-mcdougle)
- Pablo Monterde Perez (plebs)
- Jimmy Leger (redpanda)

View File

@ -46,18 +46,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%

View File

@ -87,6 +87,7 @@
"ocramius/proxy-manager": "~0.4|~1.0|~2.0",
"predis/predis": "~1.0",
"egulias/email-validator": "~1.2,>=1.2.8|~2.0",
"symfony/phpunit-bridge": "~3.2",
"symfony/polyfill-apcu": "~1.1",
"symfony/security-acl": "~2.8|~3.0",
"phpdocumentor/reflection-docblock": "^3.0"
@ -115,11 +116,6 @@
"**/Tests/"
]
},
"autoload-dev": {
"psr-4": {
"Symfony\\Bridge\\PhpUnit\\": "src/Symfony/Bridge/PhpUnit/"
}
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {

9
phpunit Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env php
<?php
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);
}
putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit');
require __DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit';

View File

@ -190,7 +190,7 @@ if (isset($argv[1]) && is_dir($argv[1]) && !file_exists($argv[1].'/phpunit.xml.d
}
if (!file_exists($component = array_pop($argv))) {
$component = basename($oldcwd);
$component = basename($oldPwd);
}
if ($exit) {

View File

@ -166,11 +166,8 @@ EOF
foreach ($operation->getDomains() as $domain) {
$newKeys = array_keys($operation->getNewMessages($domain));
$allKeys = array_keys($operation->getMessages($domain));
$domainMessagesCount = count($newKeys) + count($allKeys);
$io->section(sprintf('Messages extracted for domain "<info>%s</info>" (%d messages)', $domain, $domainMessagesCount));
$io->listing(array_merge(
$list = array_merge(
array_diff($allKeys, $newKeys),
array_map(function ($id) {
return sprintf('<fg=green>%s</>', $id);
@ -178,7 +175,12 @@ EOF
array_map(function ($id) {
return sprintf('<fg=red>%s</>', $id);
}, array_keys($operation->getObsoleteMessages($domain)))
));
);
$domainMessagesCount = count($list);
$io->section(sprintf('Messages extracted for domain "<info>%s</info>" (%d message%s)', $domain, $domainMessagesCount, $domainMessagesCount > 1 ? 's' : ''));
$io->listing($list);
$extractedMessagesCount += $domainMessagesCount;
}
@ -187,7 +189,7 @@ EOF
$io->comment('Xliff output version is <info>1.2</info>');
}
$resultMessage = sprintf('%d messages were successfully extracted', $extractedMessagesCount);
$resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was');
}
if ($input->getOption('no-backup') === true) {

View File

@ -39,7 +39,7 @@ build: 56
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 20px;
color: #313131;
word-break: break-all;
word-wrap: break-word;
}
.sf-reset li {
padding-bottom: 10px;

View File

@ -28,6 +28,15 @@ class TranslationUpdateCommandTest extends \PHPUnit_Framework_TestCase
$tester = $this->createCommandTester($this->getContainer(array('messages' => array('foo' => 'foo'))));
$tester->execute(array('command' => 'translation:update', 'locale' => 'en', 'bundle' => 'foo', '--dump-messages' => true, '--clean' => true));
$this->assertRegExp('/foo/', $tester->getDisplay());
$this->assertRegExp('/1 message was successfully extracted/', $tester->getDisplay());
}
public function testDumpTwoMessagesAndClean()
{
$tester = $this->createCommandTester($this->getContainer(array('foo' => 'foo', 'bar' => 'bar')));
$tester->execute(array('command' => 'translation:update', 'locale' => 'en', 'bundle' => 'foo', '--dump-messages' => true, '--clean' => true));
$this->assertRegExp('/foo/', $tester->getDisplay());
$this->assertRegExp('/bar/', $tester->getDisplay());
$this->assertRegExp('/2 messages were successfully extracted/', $tester->getDisplay());
}

View File

@ -55,7 +55,12 @@ class ClassCollectionLoader
$classes = array_unique($classes);
$cache = $cacheDir.'/'.$name.$extension;
// cache the core classes
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir));
}
$cacheDir = rtrim(realpath($cacheDir), '/'.DIRECTORY_SEPARATOR);
$cache = $cacheDir.DIRECTORY_SEPARATOR.$name.$extension;
// auto-reload
$reload = false;
@ -119,6 +124,16 @@ class ClassCollectionLoader
$declared[$class->getName()] = true;
}
// cache the core classes
$cacheDir = dirname($cache);
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir));
}
$c = '(?:\s*+(?:(?:#|//)[^\n]*+\n|/\*(?:(?<!\*/).)++)?+)*+';
$strictTypesRegex = str_replace('.', $c, "'^<\?php\s.declare.\(.strict_types.=.1.\).;'is");
$cacheDir = explode(DIRECTORY_SEPARATOR, $cacheDir);
$files = array();
$content = '';
foreach (self::getOrderedClasses($classes) as $class) {
@ -127,26 +142,40 @@ class ClassCollectionLoader
}
$declared[$class->getName()] = true;
$files[$class->getName()] = $class->getFileName();
$files[$class->getName()] = $file = $class->getFileName();
$c = file_get_contents($file);
$c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($class->getFileName()));
if (preg_match($strictTypesRegex, $c)) {
$file = explode(DIRECTORY_SEPARATOR, $file);
// fakes namespace declaration for global code
if (!$class->inNamespace()) {
$c = "\nnamespace\n{\n".$c."\n}\n";
for ($i = 0; isset($file[$i], $cacheDir[$i]); ++$i) {
if ($file[$i] !== $cacheDir[$i]) {
break;
}
}
if (1 >= $i) {
$file = var_export(implode(DIRECTORY_SEPARATOR, $file), true);
} else {
$file = array_slice($file, $i);
$file = str_repeat('..'.DIRECTORY_SEPARATOR, count($cacheDir) - $i).implode(DIRECTORY_SEPARATOR, $file);
$file = '__DIR__.'.var_export(DIRECTORY_SEPARATOR.$file, true);
}
$c = "\nnamespace {require $file;}";
} else {
$c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', $c);
// fakes namespace declaration for global code
if (!$class->inNamespace()) {
$c = "\nnamespace\n{\n".$c."\n}\n";
}
$c = self::fixNamespaceDeclarations('<?php '.$c);
$c = preg_replace('/^\s*<\?php/', '', $c);
}
$c = self::fixNamespaceDeclarations('<?php '.$c);
$c = preg_replace('/^\s*<\?php/', '', $c);
$content .= $c;
}
// cache the core classes
$cacheDir = dirname($cache);
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir));
}
self::writeCacheFile($cache, '<?php '.$content);
return $files;

View File

@ -218,18 +218,20 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
public function testCommentStripping()
{
if (is_file($file = sys_get_temp_dir().'/bar.php')) {
if (is_file($file = __DIR__.'/bar.php')) {
unlink($file);
}
spl_autoload_register($r = function ($class) {
if (0 === strpos($class, 'Namespaced') || 0 === strpos($class, 'Pearlike_')) {
require_once __DIR__.'/Fixtures/'.str_replace(array('\\', '_'), '/', $class).'.php';
@require_once __DIR__.'/Fixtures/'.str_replace(array('\\', '_'), '/', $class).'.php';
}
});
$strictTypes = defined('HHVM_VERSION') ? '' : "\nnamespace {require __DIR__.'/Fixtures/Namespaced/WithStrictTypes.php';}";
ClassCollectionLoader::load(
array('Namespaced\\WithComments', 'Pearlike_WithComments'),
sys_get_temp_dir(),
array('Namespaced\\WithComments', 'Pearlike_WithComments', $strictTypes ? 'Namespaced\\WithStrictTypes' : 'Namespaced\\WithComments'),
__DIR__,
'bar',
false
);
@ -269,7 +271,9 @@ public static $loaded = true;
}
}
EOF
, str_replace("<?php \n", '', file_get_contents($file)));
.$strictTypes,
str_replace(array("<?php \n", '\\\\'), array('', '/'), file_get_contents($file))
);
unlink($file);
}

View File

@ -76,6 +76,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
'Namespaced\\Foo' => realpath(__DIR__).'/Fixtures/Namespaced/Foo.php',
'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php',
'Namespaced\\WithComments' => realpath(__DIR__).'/Fixtures/Namespaced/WithComments.php',
'Namespaced\WithStrictTypes' => realpath(__DIR__).'/Fixtures/Namespaced/WithStrictTypes.php',
),
),
array(__DIR__.'/Fixtures/beta/NamespaceCollision', array(

View File

@ -0,0 +1,13 @@
<?php
/*
* foo
*/
declare (strict_types = 1);
namespace Namespaced;
class WithStrictTypes
{
}

View File

@ -36,6 +36,7 @@ use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
@ -840,17 +841,25 @@ class Application
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;

View File

@ -942,6 +942,62 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
$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();

View File

@ -17,7 +17,8 @@
],
"require": {
"php": ">=5.5.9",
"symfony/polyfill-mbstring": "~1.0"
"symfony/polyfill-mbstring": "~1.0",
"symfony/debug": "~2.7,>=2.7.2"
},
"require-dev": {
"symfony/event-dispatcher": "~2.8|~3.0",

View File

@ -56,14 +56,12 @@ class RepeatedPass implements CompilerPassInterface
*/
public function process(ContainerBuilder $container)
{
$this->repeat = false;
foreach ($this->passes as $pass) {
$pass->process($container);
}
if ($this->repeat) {
$this->process($container);
}
do {
$this->repeat = false;
foreach ($this->passes as $pass) {
$pass->process($container);
}
} while ($this->repeat);
}
/**

View File

@ -351,7 +351,8 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
{
$id = strtolower($id);
if ($this->isFrozen() && (!isset($this->definitions[$id]) || !$this->definitions[$id]->isSynthetic())) {
if ($this->isFrozen() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) {
// setting a synthetic service on a frozen container is alright
throw new BadMethodCallException(sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a frozen container is not allowed.', $id));
}

View File

@ -128,7 +128,7 @@ class GraphvizDumper extends Dumper
*
* @return array An array of edges
*/
private function findEdges($id, $arguments, $required, $name)
private function findEdges($id, array $arguments, $required, $name)
{
$edges = array();
foreach ($arguments as $argument) {
@ -244,7 +244,7 @@ class GraphvizDumper extends Dumper
*
* @return string A comma separated list of attributes
*/
private function addAttributes($attributes)
private function addAttributes(array $attributes)
{
$code = array();
foreach ($attributes as $k => $v) {
@ -261,7 +261,7 @@ class GraphvizDumper extends Dumper
*
* @return string A space separated list of options
*/
private function addOptions($options)
private function addOptions(array $options)
{
$code = array();
foreach ($options as $k => $v) {

View File

@ -374,7 +374,7 @@ class PhpDumper extends Dumper
* @throws InvalidArgumentException
* @throws RuntimeException
*/
private function addServiceInstance($id, $definition)
private function addServiceInstance($id, Definition $definition)
{
$class = $definition->getClass();
@ -422,7 +422,7 @@ class PhpDumper extends Dumper
*
* @return bool
*/
private function isSimpleInstance($id, $definition)
private function isSimpleInstance($id, Definition $definition)
{
foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) {
if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) {
@ -446,7 +446,7 @@ class PhpDumper extends Dumper
*
* @return string
*/
private function addServiceMethodCalls($id, $definition, $variableName = 'instance')
private function addServiceMethodCalls($id, Definition $definition, $variableName = 'instance')
{
$calls = '';
foreach ($definition->getMethodCalls() as $call) {
@ -461,7 +461,7 @@ class PhpDumper extends Dumper
return $calls;
}
private function addServiceProperties($id, $definition, $variableName = 'instance')
private function addServiceProperties($id, Definition $definition, $variableName = 'instance')
{
$code = '';
foreach ($definition->getProperties() as $name => $value) {
@ -481,7 +481,7 @@ class PhpDumper extends Dumper
*
* @throws ServiceCircularReferenceException when the container contains a circular reference
*/
private function addServiceInlinedDefinitionsSetup($id, $definition)
private function addServiceInlinedDefinitionsSetup($id, Definition $definition)
{
$this->referenceVariables[$id] = new Variable('instance');
@ -525,7 +525,7 @@ class PhpDumper extends Dumper
*
* @return string
*/
private function addServiceConfigurator($id, $definition, $variableName = 'instance')
private function addServiceConfigurator($id, Definition $definition, $variableName = 'instance')
{
if (!$callable = $definition->getConfigurator()) {
return '';
@ -561,7 +561,7 @@ class PhpDumper extends Dumper
*
* @return string
*/
private function addService($id, $definition)
private function addService($id, Definition $definition)
{
$this->definitionVariables = new \SplObjectStorage();
$this->referenceVariables = array();
@ -1063,7 +1063,7 @@ EOF;
*
* @throws InvalidArgumentException
*/
private function exportParameters($parameters, $path = '', $indent = 12)
private function exportParameters(array $parameters, $path = '', $indent = 12)
{
$php = array();
foreach ($parameters as $key => $value) {

View File

@ -271,7 +271,7 @@ class XmlDumper extends Dumper
* @param \DOMElement $parent
* @param string $keyAttribute
*/
private function convertParameters($parameters, $type, \DOMElement $parent, $keyAttribute = 'key')
private function convertParameters(array $parameters, $type, \DOMElement $parent, $keyAttribute = 'key')
{
$withKeys = array_keys($parameters) !== range(0, count($parameters) - 1);
foreach ($parameters as $key => $value) {
@ -317,7 +317,7 @@ class XmlDumper extends Dumper
*
* @return array
*/
private function escape($arguments)
private function escape(array $arguments)
{
$args = array();
foreach ($arguments as $k => $v) {

View File

@ -307,7 +307,7 @@ class YamlDumper extends Dumper
*
* @return array
*/
private function prepareParameters($parameters, $escape = true)
private function prepareParameters(array $parameters, $escape = true)
{
$filtered = array();
foreach ($parameters as $key => $value) {
@ -330,7 +330,7 @@ class YamlDumper extends Dumper
*
* @return array
*/
private function escape($arguments)
private function escape(array $arguments)
{
$args = array();
foreach ($arguments as $k => $v) {

View File

@ -452,9 +452,9 @@ class YamlFileLoader extends FileLoader
{
if (is_array($value)) {
$value = array_map(array($this, 'resolveServices'), $value);
} elseif (is_string($value) && 0 === strpos($value, '@=')) {
} elseif (is_string($value) && 0 === strpos($value, '@=')) {
return new Expression(substr($value, 2));
} elseif (is_string($value) && 0 === strpos($value, '@')) {
} elseif (is_string($value) && 0 === strpos($value, '@')) {
if (0 === strpos($value, '@@')) {
$value = substr($value, 1);
$invalidBehavior = null;

View File

@ -708,14 +708,12 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
$container->set('a', new \stdClass());
}
/**
* @expectedException \BadMethodCallException
*/
public function testThrowsExceptionWhenAddServiceOnAFrozenContainer()
{
$container = new ContainerBuilder();
$container->compile();
$container->set('a', new \stdClass());
$container->set('a', $foo = new \stdClass());
$this->assertSame($foo, $container->get('a'));
}
public function testNoExceptionWhenSetSyntheticServiceOnAFrozenContainer()

View File

@ -211,7 +211,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
* @expectedExcepionMessage You have requested a synthetic service ("request"). The DIC does not know how to construct this service.
* @expectedExceptionMessage You have requested a synthetic service ("request"). The DIC does not know how to construct this service.
*/
public function testGetSyntheticServiceAlwaysThrows()
{

View File

@ -133,7 +133,10 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
}
// 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);
}

View File

@ -142,6 +142,13 @@ class FormType extends BaseType
};
};
// Wrap "post_max_size_message" in a closure to translate it lazily
$uploadMaxSizeMessage = function (Options $options) {
return function () use ($options) {
return $options['post_max_size_message'];
};
};
// For any form that is not represented by a single HTML control,
// errors should bubble up by default
$errorBubbling = function (Options $options) {
@ -172,9 +179,11 @@ class FormType extends BaseType
'action' => '',
'attr' => array(),
'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
'upload_max_size_message' => $uploadMaxSizeMessage, // internal
));
$resolver->setAllowedTypes('label_attr', 'array');
$resolver->setAllowedTypes('upload_max_size_message', array('callable'));
}
/**

View File

@ -78,7 +78,7 @@ class HttpFoundationRequestHandler implements RequestHandlerInterface
$form->submit(null, false);
$form->addError(new FormError(
$form->getConfig()->getOption('post_max_size_message'),
call_user_func($form->getConfig()->getOption('upload_max_size_message')),
null,
array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize())
));

View File

@ -42,9 +42,10 @@ class UploadValidatorExtension extends AbstractTypeExtension
{
$translator = $this->translator;
$translationDomain = $this->translationDomain;
$resolver->setNormalizer('post_max_size_message', function (Options $options, $errorMessage) use ($translator, $translationDomain) {
return $translator->trans($errorMessage, array(), $translationDomain);
$resolver->setNormalizer('upload_max_size_message', function (Options $options, $message) use ($translator, $translationDomain) {
return function () use ($translator, $translationDomain, $message) {
return $translator->trans(call_user_func($message), array(), $translationDomain);
};
});
}

View File

@ -86,7 +86,7 @@ class NativeRequestHandler implements RequestHandlerInterface
$form->submit(null, false);
$form->addError(new FormError(
$form->getConfig()->getOption('post_max_size_message'),
call_user_func($form->getConfig()->getOption('upload_max_size_message')),
null,
array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize())
));

View File

@ -134,6 +134,23 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase
$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');

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
use Symfony\Component\Form\Extension\Validator\Type\UploadValidatorExtension;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\OptionsResolver\Options;
class UploadValidatorExtensionTest extends TypeTestCase
{
@ -29,10 +30,15 @@ class UploadValidatorExtensionTest extends TypeTestCase
$resolver = new OptionsResolver();
$resolver->setDefault('post_max_size_message', 'old max {{ max }}!');
$resolver->setDefault('upload_max_size_message', function (Options $options, $message) {
return function () use ($options) {
return $options['post_max_size_message'];
};
});
$extension->configureOptions($resolver);
$options = $resolver->resolve();
$this->assertEquals('translated max {{ max }}!', $options['post_max_size_message']);
$this->assertEquals('translated max {{ max }}!', call_user_func($options['upload_max_size_message']));
}
}

View File

@ -58,6 +58,7 @@ abstract class Voter implements VoterInterface
/**
* Perform a single access check operation on a given attribute, subject and token.
* It is safe to assume that $attribute and $subject already passed the "supports()" method check.
*
* @param string $attribute
* @param mixed $subject

View File

@ -65,9 +65,17 @@ class RoleHierarchy implements RoleHierarchyInterface
}
$visited[] = $role;
$this->map[$main] = array_unique(array_merge($this->map[$main], $this->hierarchy[$role]));
$additionalRoles = array_merge($additionalRoles, array_diff($this->hierarchy[$role], $visited));
foreach ($this->hierarchy[$role] as $roleToAdd) {
$this->map[$main][] = $roleToAdd;
}
foreach (array_diff($this->hierarchy[$role], $visited) as $additionalRole) {
$additionalRoles[] = $additionalRole;
}
}
$this->map[$main] = array_unique($this->map[$main]);
}
}
}