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 echo extension = redis.so >> $INI_FILE; fi;
- if [[ ! $skip && ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; 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 [ -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 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/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 - 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: 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 - 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 # 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 # 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 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 # 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 - 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 - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev
- if [[ ! $deps ]]; then composer update; else export SYMFONY_DEPRECATIONS_HELPER=weak; fi - if [[ ! $skip && $deps ]]; then export SYMFONY_DEPRECATIONS_HELPER=weak; fi
- if [[ $TRAVIS_BRANCH = master ]]; then export SYMFONY_PHPUNIT_OVERLOAD=1; fi - if [[ ! $skip && $deps ]]; then mv composer.json.phpunit composer.json; fi
- if [[ ! $PHP = hhvm* ]]; then php -i; else hhvm --php -r 'print_r($_SERVER);print_r(ini_get_all());'; 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: script:
- if [[ $skip ]]; then echo -e "\\n\\e[1;34mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m"; fi - 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) - Kris Wallsmith (kriswallsmith)
- Jakub Zalas (jakubzalas) - Jakub Zalas (jakubzalas)
- Ryan Weaver (weaverryan) - Ryan Weaver (weaverryan)
- Kévin Dunglas (dunglas)
- Javier Eguiluz (javier.eguiluz) - Javier Eguiluz (javier.eguiluz)
- Kévin Dunglas (dunglas)
- Hugo Hamon (hhamon) - Hugo Hamon (hhamon)
- Abdellatif Ait boudad (aitboudad) - Abdellatif Ait boudad (aitboudad)
- Pascal Borreli (pborreli) - 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) - Konstantin Kudryashov (everzet)
- Bilal Amarni (bamarni) - Bilal Amarni (bamarni)
- Florin Patan (florinpatan) - Florin Patan (florinpatan)
- Peter Rehm (rpet)
- Ener-Getick (energetick) - Ener-Getick (energetick)
- Peter Rehm (rpet)
- Iltar van der Berg (kjarli) - Iltar van der Berg (kjarli)
- Kevin Bond (kbond) - Kevin Bond (kbond)
- Andrej Hudec (pulzarraider) - Andrej Hudec (pulzarraider)
@ -315,6 +315,7 @@ Symfony is the result of the work of many people who made the code better
- JhonnyL - JhonnyL
- hossein zolfi (ocean) - hossein zolfi (ocean)
- Clément Gautier (clementgautier) - Clément Gautier (clementgautier)
- James Halsall (jaitsu)
- Eduardo Gulias (egulias) - Eduardo Gulias (egulias)
- giulio de donato (liuggio) - giulio de donato (liuggio)
- Stéphane PY (steph_py) - 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 - Christian Wahler
- Mathieu Lemoine - Mathieu Lemoine
- Gintautas Miselis - Gintautas Miselis
- James Halsall (jaitsu)
- David Badura (davidbadura) - David Badura (davidbadura)
- Zander Baldwin - Zander Baldwin
- Adam Harvey - Adam Harvey
@ -1302,6 +1302,7 @@ Symfony is the result of the work of many people who made the code better
- Muriel (metalmumu) - Muriel (metalmumu)
- Michael Pohlers (mick_the_big) - Michael Pohlers (mick_the_big)
- Cayetano Soriano Gallego (neoshadybeat) - Cayetano Soriano Gallego (neoshadybeat)
- Ondrej Machulda (ondram)
- Patrick McDougle (patrick-mcdougle) - Patrick McDougle (patrick-mcdougle)
- Pablo Monterde Perez (plebs) - Pablo Monterde Perez (plebs)
- Jimmy Leger (redpanda) - Jimmy Leger (redpanda)

View File

@ -46,18 +46,20 @@ install:
- echo curl.cainfo=c:\php\cacert.pem >> php.ini-max - echo curl.cainfo=c:\php\cacert.pem >> php.ini-max
- copy /Y php.ini-max php.ini - copy /Y php.ini-max php.ini
- cd c:\projects\symfony - 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 - php composer.phar self-update
- copy /Y .composer\* %APPDATA%\Composer\ - 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) - 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 - php composer.phar update --no-progress --ansi
- SET COMPOSER_ROOT_VERSION=
- php phpunit install
test_script: test_script:
- cd c:\projects\symfony - cd c:\projects\symfony
- SET X=0 - SET X=0
- copy /Y c:\php\php.ini-min c:\php\php.ini - 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 - 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% - exit %X%

View File

@ -87,6 +87,7 @@
"ocramius/proxy-manager": "~0.4|~1.0|~2.0", "ocramius/proxy-manager": "~0.4|~1.0|~2.0",
"predis/predis": "~1.0", "predis/predis": "~1.0",
"egulias/email-validator": "~1.2,>=1.2.8|~2.0", "egulias/email-validator": "~1.2,>=1.2.8|~2.0",
"symfony/phpunit-bridge": "~3.2",
"symfony/polyfill-apcu": "~1.1", "symfony/polyfill-apcu": "~1.1",
"symfony/security-acl": "~2.8|~3.0", "symfony/security-acl": "~2.8|~3.0",
"phpdocumentor/reflection-docblock": "^3.0" "phpdocumentor/reflection-docblock": "^3.0"
@ -115,11 +116,6 @@
"**/Tests/" "**/Tests/"
] ]
}, },
"autoload-dev": {
"psr-4": {
"Symfony\\Bridge\\PhpUnit\\": "src/Symfony/Bridge/PhpUnit/"
}
},
"minimum-stability": "dev", "minimum-stability": "dev",
"extra": { "extra": {
"branch-alias": { "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))) { if (!file_exists($component = array_pop($argv))) {
$component = basename($oldcwd); $component = basename($oldPwd);
} }
if ($exit) { if ($exit) {

View File

@ -166,11 +166,8 @@ EOF
foreach ($operation->getDomains() as $domain) { foreach ($operation->getDomains() as $domain) {
$newKeys = array_keys($operation->getNewMessages($domain)); $newKeys = array_keys($operation->getNewMessages($domain));
$allKeys = array_keys($operation->getMessages($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)); $list = array_merge(
$io->listing(array_merge(
array_diff($allKeys, $newKeys), array_diff($allKeys, $newKeys),
array_map(function ($id) { array_map(function ($id) {
return sprintf('<fg=green>%s</>', $id); return sprintf('<fg=green>%s</>', $id);
@ -178,7 +175,12 @@ EOF
array_map(function ($id) { array_map(function ($id) {
return sprintf('<fg=red>%s</>', $id); return sprintf('<fg=red>%s</>', $id);
}, array_keys($operation->getObsoleteMessages($domain))) }, 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; $extractedMessagesCount += $domainMessagesCount;
} }
@ -187,7 +189,7 @@ EOF
$io->comment('Xliff output version is <info>1.2</info>'); $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) { if ($input->getOption('no-backup') === true) {

View File

@ -39,7 +39,7 @@ build: 56
font-family: Georgia, "Times New Roman", Times, serif; font-family: Georgia, "Times New Roman", Times, serif;
font-size: 20px; font-size: 20px;
color: #313131; color: #313131;
word-break: break-all; word-wrap: break-word;
} }
.sf-reset li { .sf-reset li {
padding-bottom: 10px; 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 = $this->createCommandTester($this->getContainer(array('messages' => array('foo' => 'foo'))));
$tester->execute(array('command' => 'translation:update', 'locale' => 'en', 'bundle' => 'foo', '--dump-messages' => true, '--clean' => true)); $tester->execute(array('command' => 'translation:update', 'locale' => 'en', 'bundle' => 'foo', '--dump-messages' => true, '--clean' => true));
$this->assertRegExp('/foo/', $tester->getDisplay()); $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()); $this->assertRegExp('/2 messages were successfully extracted/', $tester->getDisplay());
} }

View File

@ -55,7 +55,12 @@ class ClassCollectionLoader
$classes = array_unique($classes); $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 // auto-reload
$reload = false; $reload = false;
@ -119,6 +124,16 @@ class ClassCollectionLoader
$declared[$class->getName()] = true; $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(); $files = array();
$content = ''; $content = '';
foreach (self::getOrderedClasses($classes) as $class) { foreach (self::getOrderedClasses($classes) as $class) {
@ -127,26 +142,40 @@ class ClassCollectionLoader
} }
$declared[$class->getName()] = true; $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 for ($i = 0; isset($file[$i], $cacheDir[$i]); ++$i) {
if (!$class->inNamespace()) { if ($file[$i] !== $cacheDir[$i]) {
$c = "\nnamespace\n{\n".$c."\n}\n"; 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; $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); self::writeCacheFile($cache, '<?php '.$content);
return $files; return $files;

View File

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

View File

@ -76,6 +76,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
'Namespaced\\Foo' => realpath(__DIR__).'/Fixtures/Namespaced/Foo.php', 'Namespaced\\Foo' => realpath(__DIR__).'/Fixtures/Namespaced/Foo.php',
'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php', 'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php',
'Namespaced\\WithComments' => realpath(__DIR__).'/Fixtures/Namespaced/WithComments.php', 'Namespaced\\WithComments' => realpath(__DIR__).'/Fixtures/Namespaced/WithComments.php',
'Namespaced\WithStrictTypes' => realpath(__DIR__).'/Fixtures/Namespaced/WithStrictTypes.php',
), ),
), ),
array(__DIR__.'/Fixtures/beta/NamespaceCollision', array( 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\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/** /**
@ -840,17 +841,25 @@ class Application
if ($event->commandShouldRun()) { if ($event->commandShouldRun()) {
try { try {
$e = null;
$exitCode = $command->run($input, $output); $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()); $event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode());
$this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event); $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()); $event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode());
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
throw $e; throw $x;
} }
} else { } else {
$exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; $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()); $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() public function testRunWithDispatcherSkippingCommand()
{ {
$application = new Application(); $application = new Application();

View File

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

View File

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

View File

@ -351,7 +351,8 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
{ {
$id = strtolower($id); $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)); 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 * @return array An array of edges
*/ */
private function findEdges($id, $arguments, $required, $name) private function findEdges($id, array $arguments, $required, $name)
{ {
$edges = array(); $edges = array();
foreach ($arguments as $argument) { foreach ($arguments as $argument) {
@ -244,7 +244,7 @@ class GraphvizDumper extends Dumper
* *
* @return string A comma separated list of attributes * @return string A comma separated list of attributes
*/ */
private function addAttributes($attributes) private function addAttributes(array $attributes)
{ {
$code = array(); $code = array();
foreach ($attributes as $k => $v) { foreach ($attributes as $k => $v) {
@ -261,7 +261,7 @@ class GraphvizDumper extends Dumper
* *
* @return string A space separated list of options * @return string A space separated list of options
*/ */
private function addOptions($options) private function addOptions(array $options)
{ {
$code = array(); $code = array();
foreach ($options as $k => $v) { foreach ($options as $k => $v) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -211,7 +211,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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() public function testGetSyntheticServiceAlwaysThrows()
{ {

View File

@ -133,7 +133,10 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
} }
// read timestamp into DateTime object - the formatter delivers a timestamp // 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) { } catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $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, // For any form that is not represented by a single HTML control,
// errors should bubble up by default // errors should bubble up by default
$errorBubbling = function (Options $options) { $errorBubbling = function (Options $options) {
@ -172,9 +179,11 @@ class FormType extends BaseType
'action' => '', 'action' => '',
'attr' => array(), 'attr' => array(),
'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.', '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('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->submit(null, false);
$form->addError(new FormError( $form->addError(new FormError(
$form->getConfig()->getOption('post_max_size_message'), call_user_func($form->getConfig()->getOption('upload_max_size_message')),
null, null,
array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()) array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize())
)); ));

View File

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

View File

@ -86,7 +86,7 @@ class NativeRequestHandler implements RequestHandlerInterface
$form->submit(null, false); $form->submit(null, false);
$form->addError(new FormError( $form->addError(new FormError(
$form->getConfig()->getOption('post_max_size_message'), call_user_func($form->getConfig()->getOption('upload_max_size_message')),
null, null,
array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()) 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)); $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() public function testTransformWithDifferentPatterns()
{ {
$transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, 'MM*yyyy*dd HH|mm|ss'); $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\Form\Extension\Validator\Type\UploadValidatorExtension;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\OptionsResolver\Options;
class UploadValidatorExtensionTest extends TypeTestCase class UploadValidatorExtensionTest extends TypeTestCase
{ {
@ -29,10 +30,15 @@ class UploadValidatorExtensionTest extends TypeTestCase
$resolver = new OptionsResolver(); $resolver = new OptionsResolver();
$resolver->setDefault('post_max_size_message', 'old max {{ max }}!'); $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); $extension->configureOptions($resolver);
$options = $resolver->resolve(); $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. * 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 string $attribute
* @param mixed $subject * @param mixed $subject

View File

@ -65,9 +65,17 @@ class RoleHierarchy implements RoleHierarchyInterface
} }
$visited[] = $role; $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]);
} }
} }
} }