Merge branch '2.7' into 2.8
* 2.7: [ci] Force update of ./phpunit deps [Form] Fixed: Duplicate choice labels are remembered when using "choices_as_values" = false [Process] Don't catch RuntimeException when it complicates tests debugging [appveyor] Workaround transient segfault when APCu is enabled
This commit is contained in:
commit
d94c322272
|
@ -39,7 +39,7 @@ before_install:
|
||||||
- if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then phpenv config-rm xdebug.ini; fi;
|
- if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then phpenv config-rm xdebug.ini; fi;
|
||||||
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then echo "extension = mongo.so" >> $INI_FILE; fi;
|
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then echo "extension = mongo.so" >> $INI_FILE; fi;
|
||||||
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then echo "extension = memcache.so" >> $INI_FILE; fi;
|
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then echo "extension = memcache.so" >> $INI_FILE; fi;
|
||||||
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.7 && echo "apc.enable_cli = 1" >> $INI_FILE) || echo "Let's continue without apcu extension"; fi;
|
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.8 && echo "apc.enable_cli = 1" >> $INI_FILE) || echo "Let's continue without apcu extension"; fi;
|
||||||
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then pecl install -f memcached-2.1.0 || echo "Let's continue without memcached extension"; fi;
|
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then pecl install -f memcached-2.1.0 || echo "Let's continue without memcached extension"; fi;
|
||||||
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]] && [ "$deps" = "no" ]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo "extension = $(pwd)/modules/symfony_debug.so" >> $INI_FILE); fi;
|
- if [[ "$TRAVIS_PHP_VERSION" = 5.* ]] && [ "$deps" = "no" ]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo "extension = $(pwd)/modules/symfony_debug.so" >> $INI_FILE); fi;
|
||||||
- if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then echo "extension = ldap.so" >> $INI_FILE; fi;
|
- if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then echo "extension = ldap.so" >> $INI_FILE; fi;
|
||||||
|
|
|
@ -26,8 +26,8 @@ install:
|
||||||
- IF %PHP%==1 cd ext
|
- IF %PHP%==1 cd ext
|
||||||
- IF %PHP%==1 appveyor DownloadFile http://nebm.ist.utl.pt/~glopes/misc/intl_win/php_intl-3.0.0-5.3-nts-vc9-x86.zip
|
- IF %PHP%==1 appveyor DownloadFile http://nebm.ist.utl.pt/~glopes/misc/intl_win/php_intl-3.0.0-5.3-nts-vc9-x86.zip
|
||||||
- IF %PHP%==1 7z x php_intl-3.0.0-5.3-nts-vc9-x86.zip -y >nul
|
- IF %PHP%==1 7z x php_intl-3.0.0-5.3-nts-vc9-x86.zip -y >nul
|
||||||
- IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/apcu/4.0.7/php_apcu-4.0.7-5.3-nts-vc9-x86.zip
|
- IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/apcu/4.0.8/php_apcu-4.0.8-5.3-nts-vc9-x86.zip
|
||||||
- IF %PHP%==1 7z x php_apcu-4.0.7-5.3-nts-vc9-x86.zip -y >nul
|
- IF %PHP%==1 7z x php_apcu-4.0.8-5.3-nts-vc9-x86.zip -y >nul
|
||||||
- IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/memcache/3.0.8/php_memcache-3.0.8-5.3-nts-vc9-x86.zip
|
- IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/memcache/3.0.8/php_memcache-3.0.8-5.3-nts-vc9-x86.zip
|
||||||
- IF %PHP%==1 7z x php_memcache-3.0.8-5.3-nts-vc9-x86.zip -y >nul
|
- IF %PHP%==1 7z x php_memcache-3.0.8-5.3-nts-vc9-x86.zip -y >nul
|
||||||
- IF %PHP%==1 del /Q *.zip
|
- IF %PHP%==1 del /Q *.zip
|
||||||
|
|
5
phpunit
5
phpunit
|
@ -11,7 +11,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Please update when phpunit needs to be reinstalled with fresh deps:
|
// Please update when phpunit needs to be reinstalled with fresh deps:
|
||||||
// Cache-Id-Version: 2015-11-18 14:14 UTC
|
// Cache-Id-Version: 2015-11-28 09:05 UTC
|
||||||
|
|
||||||
use Symfony\Component\Process\ProcessUtils;
|
use Symfony\Component\Process\ProcessUtils;
|
||||||
|
|
||||||
|
@ -164,7 +164,8 @@ if (isset($argv[1]) && 'symfony' === $argv[1]) {
|
||||||
unlink($file);
|
unlink($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($procStatus) {
|
// Fail on any individual component failures but ignore STATUS_STACK_BUFFER_OVERRUN (-1073740791) on Windows when APCu is enabled
|
||||||
|
if ($procStatus && ('\\' !== DIRECTORY_SEPARATOR || !extension_loaded('apcu') || !ini_get('apc.enable_cli') || -1073740791 !== $procStatus)) {
|
||||||
$exit = 1;
|
$exit = 1;
|
||||||
echo "\033[41mKO\033[0m $component\n\n";
|
echo "\033[41mKO\033[0m $component\n\n";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -238,6 +238,7 @@ class ChoiceType extends AbstractType
|
||||||
*/
|
*/
|
||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
{
|
{
|
||||||
|
$choiceLabels = array();
|
||||||
$choiceListFactory = $this->choiceListFactory;
|
$choiceListFactory = $this->choiceListFactory;
|
||||||
|
|
||||||
$emptyData = function (Options $options) {
|
$emptyData = function (Options $options) {
|
||||||
|
@ -252,6 +253,44 @@ class ChoiceType extends AbstractType
|
||||||
return $options['required'] ? null : '';
|
return $options['required'] ? null : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// BC closure, to be removed in 3.0
|
||||||
|
$choicesNormalizer = function (Options $options, $choices) use (&$choiceLabels) {
|
||||||
|
// Unset labels from previous invocations
|
||||||
|
$choiceLabels = array();
|
||||||
|
|
||||||
|
// This closure is irrelevant when "choices_as_values" is set to true
|
||||||
|
if ($options['choices_as_values']) {
|
||||||
|
return $choices;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChoiceType::normalizeLegacyChoices($choices, $choiceLabels);
|
||||||
|
|
||||||
|
return $choices;
|
||||||
|
};
|
||||||
|
|
||||||
|
// BC closure, to be removed in 3.0
|
||||||
|
$choiceLabel = function (Options $options) use (&$choiceLabels) {
|
||||||
|
// If the choices contain duplicate labels, the normalizer of the
|
||||||
|
// "choices" option stores them in the $choiceLabels variable
|
||||||
|
|
||||||
|
// Trigger the normalizer
|
||||||
|
$options->offsetGet('choices');
|
||||||
|
|
||||||
|
// Pick labels from $choiceLabels if available
|
||||||
|
// Don't invoke count() to avoid creating a copy of the array (yet)
|
||||||
|
if ($choiceLabels) {
|
||||||
|
// Don't pass the labels by reference. We do want to create a
|
||||||
|
// copy here so that every form has an own version of that
|
||||||
|
// variable (contrary to the global reference shared by all
|
||||||
|
// forms)
|
||||||
|
return function ($choice, $key) use ($choiceLabels) {
|
||||||
|
return $choiceLabels[$key];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
$choiceListNormalizer = function (Options $options, $choiceList) use ($choiceListFactory) {
|
$choiceListNormalizer = function (Options $options, $choiceList) use ($choiceListFactory) {
|
||||||
if ($choiceList) {
|
if ($choiceList) {
|
||||||
@trigger_error('The "choice_list" option is deprecated since version 2.7 and will be removed in 3.0. Use "choice_loader" instead.', E_USER_DEPRECATED);
|
@trigger_error('The "choice_list" option is deprecated since version 2.7 and will be removed in 3.0. Use "choice_loader" instead.', E_USER_DEPRECATED);
|
||||||
|
@ -330,7 +369,7 @@ class ChoiceType extends AbstractType
|
||||||
'choices' => array(),
|
'choices' => array(),
|
||||||
'choices_as_values' => false,
|
'choices_as_values' => false,
|
||||||
'choice_loader' => null,
|
'choice_loader' => null,
|
||||||
'choice_label' => null,
|
'choice_label' => $choiceLabel,
|
||||||
'choice_name' => null,
|
'choice_name' => null,
|
||||||
'choice_value' => null,
|
'choice_value' => null,
|
||||||
'choice_attr' => null,
|
'choice_attr' => null,
|
||||||
|
@ -348,6 +387,7 @@ class ChoiceType extends AbstractType
|
||||||
'choice_translation_domain' => true,
|
'choice_translation_domain' => true,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$resolver->setNormalizer('choices', $choicesNormalizer);
|
||||||
$resolver->setNormalizer('choice_list', $choiceListNormalizer);
|
$resolver->setNormalizer('choice_list', $choiceListNormalizer);
|
||||||
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
|
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
|
||||||
$resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer);
|
$resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer);
|
||||||
|
@ -471,4 +511,34 @@ class ChoiceType extends AbstractType
|
||||||
$options['choice_attr']
|
$options['choice_attr']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When "choices_as_values" is set to false, the choices are in the keys and
|
||||||
|
* their labels in the values. Labels may occur twice. The form component
|
||||||
|
* flips the choices array in the new implementation, so duplicate labels
|
||||||
|
* are lost. Store them in a utility array that is used from the
|
||||||
|
* "choice_label" closure by default.
|
||||||
|
*
|
||||||
|
* @param array $choices The choice labels indexed by choices.
|
||||||
|
* Labels are replaced by generated keys.
|
||||||
|
* @param array $choiceLabels The array that receives the choice labels
|
||||||
|
* indexed by generated keys.
|
||||||
|
* @param int|null $nextKey The next generated key.
|
||||||
|
*
|
||||||
|
* @internal Public only to be accessible from closures on PHP 5.3. Don't
|
||||||
|
* use this method, as it may be removed without notice.
|
||||||
|
*/
|
||||||
|
public static function normalizeLegacyChoices(array &$choices, array &$choiceLabels, &$nextKey = 0)
|
||||||
|
{
|
||||||
|
foreach ($choices as $choice => &$choiceLabel) {
|
||||||
|
if (is_array($choiceLabel)) {
|
||||||
|
self::normalizeLegacyChoices($choiceLabel, $choiceLabels, $nextKey);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$choiceLabels[$nextKey] = $choiceLabel;
|
||||||
|
$choices[$choice] = $nextKey;
|
||||||
|
++$nextKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1828,6 +1828,23 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
|
||||||
), $view->vars['choices']);
|
), $view->vars['choices']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group legacy
|
||||||
|
*/
|
||||||
|
public function testDuplicateChoiceLabels()
|
||||||
|
{
|
||||||
|
$form = $this->factory->create('choice', null, array(
|
||||||
|
'choices' => array('a' => 'A', 'b' => 'B', 'c' => 'A'),
|
||||||
|
));
|
||||||
|
$view = $form->createView();
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
new ChoiceView('a', 'a', 'A'),
|
||||||
|
new ChoiceView('b', 'b', 'B'),
|
||||||
|
new ChoiceView('c', 'c', 'A'),
|
||||||
|
), $view->vars['choices']);
|
||||||
|
}
|
||||||
|
|
||||||
public function testAdjustFullNameForMultipleNonExpanded()
|
public function testAdjustFullNameForMultipleNonExpanded()
|
||||||
{
|
{
|
||||||
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array(
|
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array(
|
||||||
|
|
|
@ -152,46 +152,37 @@ class SimpleProcessTest extends AbstractProcessTest
|
||||||
|
|
||||||
public function testStopTerminatesProcessCleanly()
|
public function testStopTerminatesProcessCleanly()
|
||||||
{
|
{
|
||||||
try {
|
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||||
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
$process->run(function () use ($process) {
|
||||||
$process->run(function () use ($process) {
|
$process->stop();
|
||||||
$process->stop();
|
});
|
||||||
});
|
$this->assertTrue(true, 'A call to stop() is not expected to cause wait() to throw a RuntimeException');
|
||||||
} catch (\RuntimeException $e) {
|
|
||||||
$this->fail('A call to stop() is not expected to cause wait() to throw a RuntimeException');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testKillSignalTerminatesProcessCleanly()
|
public function testKillSignalTerminatesProcessCleanly()
|
||||||
{
|
{
|
||||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||||
|
|
||||||
try {
|
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||||
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
$process->run(function () use ($process) {
|
||||||
$process->run(function () use ($process) {
|
if ($process->isRunning()) {
|
||||||
if ($process->isRunning()) {
|
$process->signal(defined('SIGKILL') ? SIGKILL : 9);
|
||||||
$process->signal(defined('SIGKILL') ? SIGKILL : 9);
|
}
|
||||||
}
|
});
|
||||||
});
|
$this->assertTrue(true, 'A call to signal() is not expected to cause wait() to throw a RuntimeException');
|
||||||
} catch (\RuntimeException $e) {
|
|
||||||
$this->fail('A call to signal() is not expected to cause wait() to throw a RuntimeException');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTermSignalTerminatesProcessCleanly()
|
public function testTermSignalTerminatesProcessCleanly()
|
||||||
{
|
{
|
||||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||||
|
|
||||||
try {
|
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||||
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
$process->run(function () use ($process) {
|
||||||
$process->run(function () use ($process) {
|
if ($process->isRunning()) {
|
||||||
if ($process->isRunning()) {
|
$process->signal(defined('SIGTERM') ? SIGTERM : 15);
|
||||||
$process->signal(defined('SIGTERM') ? SIGTERM : 15);
|
}
|
||||||
}
|
});
|
||||||
});
|
$this->assertTrue(true, 'A call to signal() is not expected to cause wait() to throw a RuntimeException');
|
||||||
} catch (\RuntimeException $e) {
|
|
||||||
$this->fail('A call to signal() is not expected to cause wait() to throw a RuntimeException');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testStopWithTimeoutIsActuallyWorking()
|
public function testStopWithTimeoutIsActuallyWorking()
|
||||||
|
|
Reference in New Issue