Merge branch '2.7' into 2.8

* 2.7:
  use HHVM 3.15 to run tests
  [TwigBridge] fix Twig 2.x compatibility
  removed some PHP CS Fixer rules
  Improve language
  [Console] SymfonyStyle: Escape trailing backslashes in user texts
  Mention the community review guide
  [Form] fix group sequence based validation
  [Console] Fix question formatting using SymfonyStyle::ask()
This commit is contained in:
Christian Flothmann 2016-12-23 17:32:24 +01:00
commit 8a27d79a10
16 changed files with 138 additions and 49 deletions

View File

@ -5,6 +5,8 @@ return PhpCsFixer\Config::create()
'@Symfony' => true,
'@Symfony:risky' => true,
'array_syntax' => array('syntax' => 'long'),
'no_unreachable_default_argument_value' => false,
'heredoc_to_nowdoc' => false,
))
->setRiskyAllowed(true)
->setFinder(

View File

@ -18,7 +18,7 @@ env:
matrix:
include:
# Use the newer stack for HHVM as HHVM does not support Precise anymore since a long time and so Precise has an outdated version
- php: hhvm-stable
- php: hhvm-3.15
sudo: required
dist: trusty
group: edge

View File

@ -5,6 +5,7 @@ Symfony is an open source, community-driven project.
If you'd like to contribute, please read the following documents:
* [Reviewing issues/pull requests][0]
* [Reporting a Bug][1]
* [Submitting a Patch][2]
* [Symfony Core Team][3]
@ -14,6 +15,7 @@ If you'd like to contribute, please read the following documents:
* [Coding Standards][7]
* [Conventions][8]
[0]: https://symfony.com/doc/current/contributing/community/reviews.html
[1]: https://symfony.com/doc/current/contributing/code/bugs.html
[2]: https://symfony.com/doc/current/contributing/code/patches.html
[3]: https://symfony.com/doc/current/contributing/code/core_team.html

View File

@ -41,6 +41,14 @@ please read the [Contributing Code][3] part of the documentation. If you're subm
a pull request, please follow the guidelines in the [Submitting a Patch][4] section
and use [Pull Request Template][5].
Community Reviews
-----------------
If you don't feel ready to contribute code or patches, reviewing issues and pull
requests can be a great start to get involved and give back. In fact, people who
"triage" issues are the backbone to Symfony's success!
More information can be found in the [Community Reviews][8] guide.
Running Symfony Tests
----------------------
@ -54,3 +62,4 @@ Information on how to run the Symfony test suite can be found in the
[5]: https://symfony.com/doc/current/contributing/code/patches.html#make-a-pull-request
[6]: https://symfony.com/doc/master/contributing/code/tests.html
[7]: https://symfony.com/doc/current/book/installation.html#installing-the-symfony-installer
[8]: https://symfony.com/doc/current/contributing/community/reviews.html

View File

@ -53,7 +53,7 @@ class TransNodeTest extends \PHPUnit_Framework_TestCase
protected function getVariableGetterWithStrictCheck($name)
{
if (\Twig_Environment::MAJOR_VERSION >= 2) {
return sprintf('(isset($context["%s"]) || array_key_exists("%s", $context) ? $context["%s"] : $this->notFound("%s", 0))', $name, $name, $name, $name);
return sprintf('(isset($context["%s"]) || array_key_exists("%s", $context) ? $context["%s"] : (function () { throw new Twig_Error_Runtime(\'Variable "%s" does not exist.\', 0, $this->getSourceContext()); })())', $name, $name, $name, $name);
}
if (PHP_VERSION_ID >= 70000) {

View File

@ -35,6 +35,20 @@ class OutputFormatter implements OutputFormatterInterface
{
$text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);
return self::escapeTrailingBackslash($text);
}
/**
* Escapes trailing "\" in given text.
*
* @param string $text Text to escape
*
* @return string Escaped text
*
* @internal
*/
public static function escapeTrailingBackslash($text)
{
if ('\\' === substr($text, -1)) {
$len = strlen($text);
$text = rtrim($text, '\\');

View File

@ -54,7 +54,7 @@ class SymfonyQuestionHelper extends QuestionHelper
*/
protected function writePrompt(OutputInterface $output, Question $question)
{
$text = OutputFormatter::escape($question->getQuestion());
$text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
$default = $question->getDefault();
switch (true) {

View File

@ -79,7 +79,7 @@ class SymfonyStyle extends OutputStyle
{
$this->autoPrependBlock();
$this->writeln(array(
sprintf('<comment>%s</>', $message),
sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
));
$this->newLine();
@ -92,7 +92,7 @@ class SymfonyStyle extends OutputStyle
{
$this->autoPrependBlock();
$this->writeln(array(
sprintf('<comment>%s</>', $message),
sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
sprintf('<comment>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
));
$this->newLine();

View File

@ -0,0 +1,13 @@
<?php
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Tests\Style\SymfonyStyleWithForcedLineLength;
//Ensure symfony style helper methods handle trailing backslashes properly when decorating user texts
return function (InputInterface $input, OutputInterface $output) {
$output = new SymfonyStyleWithForcedLineLength($input, $output);
$output->title('Title ending with \\');
$output->section('Section ending with \\');
};

View File

@ -0,0 +1,7 @@
Title ending with \
===================
Section ending with \
---------------------

View File

@ -92,13 +92,22 @@ class SymfonyQuestionHelperTest extends \PHPUnit_Framework_TestCase
$this->assertOutputContains('Can I have a backslash? [\]', $output);
}
public function testAskEscapeLabel()
public function testAskEscapeAndFormatLabel()
{
$helper = new SymfonyQuestionHelper();
$helper->setInputStream($this->getInputStream('Foo\\Bar'));
$helper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), new Question('Do you want to use Foo\\Bar <comment>or</comment> Foo\\Baz\\?', 'Foo\\Baz'));
$this->assertOutputContains('Do you want to use Foo\\Bar or Foo\\Baz\\? [Foo\\Baz]:', $output);
}
public function testLabelTrailingBackslash()
{
$helper = new SymfonyQuestionHelper();
$helper->setInputStream($this->getInputStream('sure'));
$helper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), new Question('Do you want a \?'));
$helper->ask($this->createInputInterfaceMock(), $output = $this->createOutputInterface(), new Question('Question with a trailing \\'));
$this->assertOutputContains('Do you want a \?', $output);
$this->assertOutputContains('Question with a trailing \\', $output);
}
/**

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Extension\Validator\Constraints;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\GroupSequence;
use Symfony\Component\Validator\Constraints\Valid;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
@ -50,10 +51,12 @@ class FormValidator extends ConstraintValidator
// Validate the data against its own constraints
if (self::allowDataWalking($form)) {
foreach ($groups as $group) {
if ($validator) {
$validator->atPath('data')->validate($form->getData(), null, $group);
} else {
if ($validator) {
if (is_array($groups) && count($groups) > 0 || $groups instanceof GroupSequence && count($groups->groups) > 0) {
$validator->atPath('data')->validate($form->getData(), null, $groups);
}
} else {
foreach ($groups as $group) {
// 2.4 API
$this->context->validate($form->getData(), 'data', $group, true);
}
@ -233,6 +236,10 @@ class FormValidator extends ConstraintValidator
$groups = call_user_func($groups, $form);
}
if ($groups instanceof GroupSequence) {
return $groups;
}
return (array) $groups;
}
}

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Form\Extension\Validator\Type;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\GroupSequence;
/**
* Encapsulates common logic of {@link FormTypeValidatorExtension} and
@ -42,6 +43,10 @@ abstract class BaseValidatorExtension extends AbstractTypeExtension
return $groups;
}
if ($groups instanceof GroupSequence) {
return $groups;
}
return (array) $groups;
};

View File

@ -18,6 +18,7 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
use Symfony\Component\Form\SubmitButtonBuilder;
use Symfony\Component\Validator\Constraints\GroupSequence;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Valid;
@ -72,8 +73,7 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
->setData($object)
->getForm();
$this->expectValidateAt(0, 'data', $object, 'group1');
$this->expectValidateAt(1, 'data', $object, 'group2');
$this->expectValidateAt(0, 'data', $object, array('group1', 'group2'));
$this->validator->validate($form, new Form());
@ -95,12 +95,11 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
->getForm();
// First default constraints
$this->expectValidateAt(0, 'data', $object, 'group1');
$this->expectValidateAt(1, 'data', $object, 'group2');
$this->expectValidateAt(0, 'data', $object, array('group1', 'group2'));
// Then custom constraints
$this->expectValidateValueAt(2, 'data', $object, $constraint1, 'group1');
$this->expectValidateValueAt(3, 'data', $object, $constraint2, 'group2');
$this->expectValidateValueAt(1, 'data', $object, $constraint1, 'group1');
$this->expectValidateValueAt(2, 'data', $object, $constraint2, 'group2');
$this->validator->validate($form, new Form());
@ -121,8 +120,7 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
$form->setData($object);
$this->expectValidateAt(0, 'data', $object, 'group1');
$this->expectValidateAt(1, 'data', $object, 'group2');
$this->expectValidateAt(0, 'data', $object, array('group1', 'group2'));
$this->validator->validate($form, new Form());
@ -180,7 +178,7 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
$form = new FormBuilder('name', '\stdClass', $this->dispatcher, $this->factory);
$form = $form->setData($object)->getForm();
$this->expectValidateAt(0, 'data', $object, 'Default');
$this->expectValidateAt(0, 'data', $object, array('Default'));
$this->validator->validate($form, new Form());
@ -392,6 +390,21 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
}
public function testHandleCallbackValidationGroups()
{
$object = $this->getMockBuilder('\stdClass')->getMock();
$options = array('validation_groups' => new GroupSequence(array('group1', 'group2')));
$form = $this->getBuilder('name', '\stdClass', $options)
->setData($object)
->getForm();
$this->expectValidateAt(0, 'data', $object, new GroupSequence(array('group1', 'group2')));
$this->validator->validate($form, new Form());
$this->assertNoViolation();
}
public function testHandleGroupSequenceValidationGroups()
{
$object = $this->getMockBuilder('\stdClass')->getMock();
$options = array('validation_groups' => array($this, 'getValidationGroups'));
@ -399,8 +412,7 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
->setData($object)
->getForm();
$this->expectValidateAt(0, 'data', $object, 'group1');
$this->expectValidateAt(1, 'data', $object, 'group2');
$this->expectValidateAt(0, 'data', $object, array('group1', 'group2'));
$this->validator->validate($form, new Form());
@ -415,7 +427,7 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
->setData($object)
->getForm();
$this->expectValidateAt(0, 'data', $object, 'header');
$this->expectValidateAt(0, 'data', $object, array('header'));
$this->validator->validate($form, new Form());
@ -432,8 +444,7 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
->setData($object)
->getForm();
$this->expectValidateAt(0, 'data', $object, 'group1');
$this->expectValidateAt(1, 'data', $object, 'group2');
$this->expectValidateAt(0, 'data', $object, array('group1', 'group2'));
$this->validator->validate($form, new Form());
@ -571,7 +582,7 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
->setData($object)
->getForm();
$this->expectValidateAt(0, 'data', $object, 'Default');
$this->expectValidateAt(0, 'data', $object, array('Default'));
$this->validator->validate($form, new Form());

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
use Symfony\Component\Form\Test\FormInterface;
use Symfony\Component\Validator\Constraints\GroupSequence;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
@ -70,5 +71,14 @@ abstract class BaseValidatorExtensionTest extends TypeTestCase
$this->assertInternalType('callable', $form->getConfig()->getOption('validation_groups'));
}
public function testValidationGroupsCanBeSetToGroupSequence()
{
$form = $this->createForm(array(
'validation_groups' => new GroupSequence(array('group1', 'group2')),
));
$this->assertInstanceOf('Symfony\Component\Validator\Constraints\GroupSequence', $form->getConfig()->getOption('validation_groups'));
}
abstract protected function createForm(array $options = array());
}

View File

@ -12,11 +12,11 @@
</trans-unit>
<trans-unit id="3">
<source>This value should be of type {{ type }}.</source>
<target>Verdien må være av typen {{ type }}.</target>
<target>Verdien skal ha typen {{ type }}.</target>
</trans-unit>
<trans-unit id="4">
<source>This value should be blank.</source>
<target>Verdien være blank.</target>
<target>Verdien skal være blank.</target>
</trans-unit>
<trans-unit id="5">
<source>The value you selected is not a valid choice.</source>
@ -88,19 +88,19 @@
</trans-unit>
<trans-unit id="22">
<source>This value should not be blank.</source>
<target>Verdien ikke være blank.</target>
<target>Verdien kan ikke være blank.</target>
</trans-unit>
<trans-unit id="23">
<source>This value should not be null.</source>
<target>Verdien ikke være tom (null).</target>
<target>Verdien kan ikke være tom (null).</target>
</trans-unit>
<trans-unit id="24">
<source>This value should be null.</source>
<target>Verdien være tom (null).</target>
<target>Verdien skal være tom (null).</target>
</trans-unit>
<trans-unit id="25">
<source>This value is not valid.</source>
<target>Verdien er ikke gyldig.</target>
<target>Verdien er ugyldig.</target>
</trans-unit>
<trans-unit id="26">
<source>This value is not a valid time.</source>
@ -112,7 +112,7 @@
</trans-unit>
<trans-unit id="31">
<source>The two values should be equal.</source>
<target>Verdiene være identiske.</target>
<target>Verdiene skal være identiske.</target>
</trans-unit>
<trans-unit id="32">
<source>The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.</source>
@ -128,7 +128,7 @@
</trans-unit>
<trans-unit id="35">
<source>This value should be a valid number.</source>
<target>Verdien være et gyldig tall.</target>
<target>Verdien skal være et gyldig tall.</target>
</trans-unit>
<trans-unit id="36">
<source>This file is not a valid image.</source>
@ -176,11 +176,11 @@
</trans-unit>
<trans-unit id="47">
<source>This value should be the user's current password.</source>
<target>Verdien være brukerens sitt nåværende passord.</target>
<target>Verdien skal være brukerens sitt nåværende passord.</target>
</trans-unit>
<trans-unit id="48">
<source>This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.</source>
<target>Verdien være nøyaktig {{ limit }} tegn.</target>
<target>Verdien skal være nøyaktig {{ limit }} tegn.</target>
</trans-unit>
<trans-unit id="49">
<source>The file was only partially uploaded.</source>
@ -220,11 +220,11 @@
</trans-unit>
<trans-unit id="58">
<source>Unsupported card type or invalid card number.</source>
<target>Korttypen er ikke støttet eller ugyldig kortnummer.</target>
<target>Korttypen er ikke støttet eller kortnummeret er ugyldig.</target>
</trans-unit>
<trans-unit id="59">
<source>This is not a valid International Bank Account Number (IBAN).</source>
<target>Dette er ikke en gyldig IBAN.</target>
<target>Dette er ikke et gyldig IBAN-nummer.</target>
</trans-unit>
<trans-unit id="60">
<source>This value is not a valid ISBN-10.</source>
@ -248,43 +248,43 @@
</trans-unit>
<trans-unit id="65">
<source>This value should be equal to {{ compared_value }}.</source>
<target>Verdien være lik {{ compared_value }}.</target>
<target>Verdien skal være lik {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="66">
<source>This value should be greater than {{ compared_value }}.</source>
<target>Verdien være større enn {{ compared_value }}.</target>
<target>Verdien skal være større enn {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="67">
<source>This value should be greater than or equal to {{ compared_value }}.</source>
<target>Verdien være større enn eller lik {{ compared_value }}.</target>
<target>Verdien skal være større enn eller lik {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="68">
<source>This value should be identical to {{ compared_value_type }} {{ compared_value }}.</source>
<target>Verdien være identisk med {{ compared_value_type }} {{ compared_value }}.</target>
<target>Verdien skal være identisk med {{ compared_value_type }} {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="69">
<source>This value should be less than {{ compared_value }}.</source>
<target>Verdien være mindre enn {{ compared_value }}.</target>
<target>Verdien skal være mindre enn {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="70">
<source>This value should be less than or equal to {{ compared_value }}.</source>
<target>Verdien være mindre enn eller lik {{ compared_value }}.</target>
<target>Verdien skal være mindre enn eller lik {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="71">
<source>This value should not be equal to {{ compared_value }}.</source>
<target>Verdien ikke være lik {{ compared_value }}.</target>
<target>Verdien skal ikke være lik {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="72">
<source>This value should not be identical to {{ compared_value_type }} {{ compared_value }}.</source>
<target>Verdien ikke være identisk med {{ compared_value_type }} {{ compared_value }}.</target>
<target>Verdien skal ikke være identisk med {{ compared_value_type }} {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="73">
<source>The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}.</source>
<target>Bildeforholdet er for stort ({{ ratio }}). Tillatt maksimumsbildeforhold er {{ max_ratio }}.</target>
<target>Bildeforholdet er for stort ({{ ratio }}). Tillatt bildeforhold er maks {{ max_ratio }}.</target>
</trans-unit>
<trans-unit id="74">
<source>The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}.</source>
<target>Bildeforholdet er for lite ({{ ratio }}). Forventet maksimumsbildeforhold er {{ min_ratio }}.</target>
<target>Bildeforholdet er for lite ({{ ratio }}). Forventet bildeforhold er minst {{ min_ratio }}.</target>
</trans-unit>
<trans-unit id="75">
<source>The image is square ({{ width }}x{{ height }}px). Square images are not allowed.</source>