Merge branch '5.0'
* 5.0: [HttpFoundation] workaround PHP bug in the session module [SecurityBundle] fix accepting env vars in remember-me configurations [Form] Fixed handling groups sequence validation [Mime] Ensure proper line-ending for SMIME [Cache] Avoid memory leak in TraceableAdapter::reset()
This commit is contained in:
commit
69b6c90330
@ -244,15 +244,11 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
|
|||||||
*/
|
*/
|
||||||
public function reset()
|
public function reset()
|
||||||
{
|
{
|
||||||
if (!$this->pool instanceof ResetInterface) {
|
if ($this->pool instanceof ResetInterface) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
$event = $this->start(__FUNCTION__);
|
|
||||||
try {
|
|
||||||
$this->pool->reset();
|
$this->pool->reset();
|
||||||
} finally {
|
|
||||||
$event->end = microtime(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->clearCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,6 +24,8 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
|||||||
*/
|
*/
|
||||||
class FormValidator extends ConstraintValidator
|
class FormValidator extends ConstraintValidator
|
||||||
{
|
{
|
||||||
|
private $resolvedGroups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -44,44 +46,70 @@ class FormValidator extends ConstraintValidator
|
|||||||
|
|
||||||
if ($form->isSubmitted() && $form->isSynchronized()) {
|
if ($form->isSubmitted() && $form->isSynchronized()) {
|
||||||
// Validate the form data only if transformation succeeded
|
// Validate the form data only if transformation succeeded
|
||||||
$groups = self::getValidationGroups($form);
|
$groups = $this->getValidationGroups($form);
|
||||||
|
|
||||||
if (!$groups) {
|
if (!$groups) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $form->getData();
|
$data = $form->getData();
|
||||||
|
|
||||||
// Validate the data against its own constraints
|
// Validate the data against its own constraints
|
||||||
if ($form->isRoot() && (\is_object($data) || \is_array($data))) {
|
$validateDataGraph = $form->isRoot()
|
||||||
if (($groups && \is_array($groups)) || ($groups instanceof GroupSequence && $groups->groups)) {
|
&& (\is_object($data) || \is_array($data))
|
||||||
$validator->atPath('data')->validate($form->getData(), null, $groups);
|
&& (($groups && \is_array($groups)) || ($groups instanceof GroupSequence && $groups->groups))
|
||||||
}
|
;
|
||||||
}
|
|
||||||
|
|
||||||
// Validate the data against the constraints defined
|
// Validate the data against the constraints defined in the form
|
||||||
// in the form
|
/** @var Constraint[] $constraints */
|
||||||
$constraints = $config->getOption('constraints', []);
|
$constraints = $config->getOption('constraints', []);
|
||||||
|
|
||||||
if ($groups instanceof GroupSequence) {
|
if ($groups instanceof GroupSequence) {
|
||||||
$validator->atPath('data')->validate($form->getData(), $constraints, $groups);
|
// Validate the data, the form AND nested fields in sequence
|
||||||
// Otherwise validate a constraint only once for the first
|
$violationsCount = $this->context->getViolations()->count();
|
||||||
// matching group
|
$fieldPropertyPath = \is_object($data) ? 'children[%s]' : 'children%s';
|
||||||
foreach ($groups as $group) {
|
$hasChildren = $form->count() > 0;
|
||||||
if (\in_array($group, $formConstraint->groups)) {
|
$this->resolvedGroups = $hasChildren ? new \SplObjectStorage() : null;
|
||||||
$validator->atPath('data')->validate($form->getData(), $formConstraint, $group);
|
|
||||||
if (\count($this->context->getViolations()) > 0) {
|
foreach ($groups->groups as $group) {
|
||||||
|
if ($validateDataGraph) {
|
||||||
|
$validator->atPath('data')->validate($data, null, $group);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($groupedConstraints = self::getConstraintsInGroups($constraints, $group)) {
|
||||||
|
$validator->atPath('data')->validate($data, $groupedConstraints, $group);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($form->all() as $field) {
|
||||||
|
if ($field->isSubmitted()) {
|
||||||
|
// remember to validate this field is one group only
|
||||||
|
// otherwise resolving the groups would reuse the same
|
||||||
|
// sequence recursively, thus some fields could fail
|
||||||
|
// in different steps without breaking early enough
|
||||||
|
$this->resolvedGroups[$field] = (array) $group;
|
||||||
|
$validator->atPath(sprintf($fieldPropertyPath, $field->getPropertyPath()))->validate($field, $formConstraint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($violationsCount < $this->context->getViolations()->count()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($hasChildren) {
|
||||||
|
// destroy storage at the end of the sequence to avoid memory leaks
|
||||||
|
$this->resolvedGroups = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if ($validateDataGraph) {
|
||||||
|
$validator->atPath('data')->validate($data, null, $groups);
|
||||||
|
}
|
||||||
|
|
||||||
$groupedConstraints = [];
|
$groupedConstraints = [];
|
||||||
|
|
||||||
foreach ($constraints as $constraint) {
|
foreach ($constraints as $constraint) {
|
||||||
// For the "Valid" constraint, validate the data in all groups
|
// For the "Valid" constraint, validate the data in all groups
|
||||||
if ($constraint instanceof Valid) {
|
if ($constraint instanceof Valid) {
|
||||||
$validator->atPath('data')->validate($form->getData(), $constraint, $groups);
|
$validator->atPath('data')->validate($data, $constraint, $groups);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -101,7 +129,7 @@ class FormValidator extends ConstraintValidator
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($groupedConstraints as $group => $constraint) {
|
foreach ($groupedConstraints as $group => $constraint) {
|
||||||
$validator->atPath('data')->validate($form->getData(), $constraint, $group);
|
$validator->atPath('data')->validate($data, $constraint, $group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif (!$form->isSynchronized()) {
|
} elseif (!$form->isSynchronized()) {
|
||||||
@ -160,7 +188,7 @@ class FormValidator extends ConstraintValidator
|
|||||||
*
|
*
|
||||||
* @return string|GroupSequence|(string|GroupSequence)[] The validation groups
|
* @return string|GroupSequence|(string|GroupSequence)[] The validation groups
|
||||||
*/
|
*/
|
||||||
private static function getValidationGroups(FormInterface $form)
|
private function getValidationGroups(FormInterface $form)
|
||||||
{
|
{
|
||||||
// Determine the clicked button of the complete form tree
|
// Determine the clicked button of the complete form tree
|
||||||
$clickedButton = null;
|
$clickedButton = null;
|
||||||
@ -184,6 +212,10 @@ class FormValidator extends ConstraintValidator
|
|||||||
return self::resolveValidationGroups($groups, $form);
|
return self::resolveValidationGroups($groups, $form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($this->resolvedGroups[$form])) {
|
||||||
|
return $this->resolvedGroups[$form];
|
||||||
|
}
|
||||||
|
|
||||||
$form = $form->getParent();
|
$form = $form->getParent();
|
||||||
} while (null !== $form);
|
} while (null !== $form);
|
||||||
|
|
||||||
@ -209,4 +241,11 @@ class FormValidator extends ConstraintValidator
|
|||||||
|
|
||||||
return (array) $groups;
|
return (array) $groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function getConstraintsInGroups($constraints, $group)
|
||||||
|
{
|
||||||
|
return array_filter($constraints, static function (Constraint $constraint) use ($group) {
|
||||||
|
return \in_array($group, $constraint->groups, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,8 +444,8 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
|||||||
$form = $this->getCompoundForm($object, $options);
|
$form = $this->getCompoundForm($object, $options);
|
||||||
$form->submit([]);
|
$form->submit([]);
|
||||||
|
|
||||||
$this->expectValidateAt(0, 'data', $object, new GroupSequence(['group1', 'group2']));
|
$this->expectValidateAt(0, 'data', $object, 'group1');
|
||||||
$this->expectValidateAt(1, 'data', $object, new GroupSequence(['group1', 'group2']));
|
$this->expectValidateAt(1, 'data', $object, 'group2');
|
||||||
|
|
||||||
$this->validator->validate($form, new Form());
|
$this->validator->validate($form, new Form());
|
||||||
|
|
||||||
@ -801,6 +801,39 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
|||||||
$this->assertSame('data[field2]', $context->getViolations()[1]->getPropertyPath());
|
$this->assertSame('data[field2]', $context->getViolations()[1]->getPropertyPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCompositeConstraintValidatedInSequence()
|
||||||
|
{
|
||||||
|
$form = $this->getCompoundForm([], [
|
||||||
|
'constraints' => [
|
||||||
|
new Collection([
|
||||||
|
'field1' => new NotBlank([
|
||||||
|
'groups' => ['field1'],
|
||||||
|
]),
|
||||||
|
'field2' => new NotBlank([
|
||||||
|
'groups' => ['field2'],
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
'validation_groups' => new GroupSequence(['field1', 'field2']),
|
||||||
|
])
|
||||||
|
->add($this->getForm('field1'))
|
||||||
|
->add($this->getForm('field2'))
|
||||||
|
;
|
||||||
|
|
||||||
|
$form->submit([
|
||||||
|
'field1' => '',
|
||||||
|
'field2' => '',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$context = new ExecutionContext(Validation::createValidator(), $form, new IdentityTranslator());
|
||||||
|
$this->validator->initialize($context);
|
||||||
|
$this->validator->validate($form, new Form());
|
||||||
|
|
||||||
|
$this->assertCount(1, $context->getViolations());
|
||||||
|
$this->assertSame('This value should not be blank.', $context->getViolations()[0]->getMessage());
|
||||||
|
$this->assertSame('data[field1]', $context->getViolations()[0]->getPropertyPath());
|
||||||
|
}
|
||||||
|
|
||||||
protected function createValidator()
|
protected function createValidator()
|
||||||
{
|
{
|
||||||
return new FormValidator();
|
return new FormValidator();
|
||||||
@ -823,7 +856,7 @@ class FormValidatorTest extends ConstraintValidatorTestCase
|
|||||||
|
|
||||||
private function getCompoundForm($data, array $options = [])
|
private function getCompoundForm($data, array $options = [])
|
||||||
{
|
{
|
||||||
return $this->getBuilder('name', \get_class($data), $options)
|
return $this->getBuilder('name', \is_object($data) ? \get_class($data) : null, $options)
|
||||||
->setData($data)
|
->setData($data)
|
||||||
->setCompound(true)
|
->setCompound(true)
|
||||||
->setDataMapper(new PropertyPathMapper())
|
->setDataMapper(new PropertyPathMapper())
|
||||||
|
@ -12,15 +12,19 @@
|
|||||||
namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
|
namespace Symfony\Component\Form\Tests\Extension\Validator\Type;
|
||||||
|
|
||||||
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
|
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
|
||||||
|
use Symfony\Component\Form\Form;
|
||||||
use Symfony\Component\Form\Forms;
|
use Symfony\Component\Form\Forms;
|
||||||
use Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait;
|
use Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait;
|
||||||
use Symfony\Component\Form\Tests\Extension\Core\Type\FormTypeTest;
|
use Symfony\Component\Form\Tests\Extension\Core\Type\FormTypeTest;
|
||||||
use Symfony\Component\Form\Tests\Extension\Core\Type\TextTypeTest;
|
use Symfony\Component\Form\Tests\Extension\Core\Type\TextTypeTest;
|
||||||
use Symfony\Component\Validator\Constraints\Email;
|
use Symfony\Component\Form\Tests\Fixtures\Author;
|
||||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||||
use Symfony\Component\Validator\Constraints\Length;
|
use Symfony\Component\Validator\Constraints\Length;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
use Symfony\Component\Validator\Constraints\Valid;
|
use Symfony\Component\Validator\Constraints\Valid;
|
||||||
use Symfony\Component\Validator\ConstraintViolationList;
|
use Symfony\Component\Validator\ConstraintViolationList;
|
||||||
|
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||||
|
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
|
||||||
use Symfony\Component\Validator\Validation;
|
use Symfony\Component\Validator\Validation;
|
||||||
|
|
||||||
class FormTypeValidatorExtensionTest extends BaseValidatorExtensionTest
|
class FormTypeValidatorExtensionTest extends BaseValidatorExtensionTest
|
||||||
@ -64,14 +68,71 @@ class FormTypeValidatorExtensionTest extends BaseValidatorExtensionTest
|
|||||||
->add('field', TextTypeTest::TESTED_TYPE, [
|
->add('field', TextTypeTest::TESTED_TYPE, [
|
||||||
'constraints' => [
|
'constraints' => [
|
||||||
new Length(['min' => 10, 'allowEmptyString' => true, 'groups' => ['First']]),
|
new Length(['min' => 10, 'allowEmptyString' => true, 'groups' => ['First']]),
|
||||||
new Email(['groups' => ['Second']]),
|
new NotBlank(['groups' => ['Second']]),
|
||||||
],
|
],
|
||||||
])
|
])
|
||||||
;
|
;
|
||||||
|
|
||||||
$form->submit(['field' => 'wrong']);
|
$form->submit(['field' => 'wrong']);
|
||||||
|
|
||||||
$this->assertCount(1, $form->getErrors(true));
|
$errors = $form->getErrors(true);
|
||||||
|
|
||||||
|
$this->assertCount(1, $errors);
|
||||||
|
$this->assertInstanceOf(Length::class, $errors[0]->getCause()->getConstraint());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testManyFieldsGroupSequenceWithConstraintsOption()
|
||||||
|
{
|
||||||
|
$allowEmptyString = property_exists(Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
|
||||||
|
|
||||||
|
$formMetadata = new ClassMetadata(Form::class);
|
||||||
|
$authorMetadata = (new ClassMetadata(Author::class))
|
||||||
|
->addPropertyConstraint('firstName', new NotBlank(['groups' => 'Second']))
|
||||||
|
;
|
||||||
|
$metadataFactory = $this->createMock(MetadataFactoryInterface::class);
|
||||||
|
$metadataFactory->expects($this->any())
|
||||||
|
->method('getMetadataFor')
|
||||||
|
->willReturnCallback(static function ($classOrObject) use ($formMetadata, $authorMetadata) {
|
||||||
|
if (Author::class === $classOrObject || $classOrObject instanceof Author) {
|
||||||
|
return $authorMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Form::class === $classOrObject || $classOrObject instanceof Form) {
|
||||||
|
return $formMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ClassMetadata(\is_string($classOrObject) ? $classOrObject : \get_class($classOrObject));
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
$validator = Validation::createValidatorBuilder()
|
||||||
|
->setMetadataFactory($metadataFactory)
|
||||||
|
->getValidator()
|
||||||
|
;
|
||||||
|
$form = Forms::createFormFactoryBuilder()
|
||||||
|
->addExtension(new ValidatorExtension($validator))
|
||||||
|
->getFormFactory()
|
||||||
|
->create(FormTypeTest::TESTED_TYPE, new Author(), (['validation_groups' => new GroupSequence(['First', 'Second'])]))
|
||||||
|
->add('firstName', TextTypeTest::TESTED_TYPE)
|
||||||
|
->add('lastName', TextTypeTest::TESTED_TYPE, [
|
||||||
|
'constraints' => [
|
||||||
|
new Length(['min' => 10, 'groups' => ['First']] + $allowEmptyString),
|
||||||
|
],
|
||||||
|
])
|
||||||
|
->add('australian', TextTypeTest::TESTED_TYPE, [
|
||||||
|
'constraints' => [
|
||||||
|
new NotBlank(['groups' => ['Second']]),
|
||||||
|
],
|
||||||
|
])
|
||||||
|
;
|
||||||
|
|
||||||
|
$form->submit(['firstName' => '', 'lastName' => 'wrong_1', 'australian' => '']);
|
||||||
|
|
||||||
|
$errors = $form->getErrors(true);
|
||||||
|
|
||||||
|
$this->assertCount(1, $errors);
|
||||||
|
$this->assertInstanceOf(Length::class, $errors[0]->getCause()->getConstraint());
|
||||||
|
$this->assertSame('children[lastName].data', $errors[0]->getCause()->getPropertyPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function createForm(array $options = [])
|
protected function createForm(array $options = [])
|
||||||
|
@ -13,6 +13,8 @@ namespace Symfony\Component\Form\Tests\Extension\Validator;
|
|||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\Extension\Validator\Constraints\Form as FormConstraint;
|
use Symfony\Component\Form\Extension\Validator\Constraints\Form as FormConstraint;
|
||||||
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
|
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
|
||||||
use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser;
|
use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser;
|
||||||
@ -20,6 +22,8 @@ use Symfony\Component\Form\Form;
|
|||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\Form\FormFactoryBuilder;
|
use Symfony\Component\Form\FormFactoryBuilder;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||||
|
use Symfony\Component\Validator\Constraints\Length;
|
||||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
use Symfony\Component\Validator\Mapping\CascadingStrategy;
|
use Symfony\Component\Validator\Mapping\CascadingStrategy;
|
||||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||||
@ -49,6 +53,8 @@ class ValidatorExtensionTest extends TestCase
|
|||||||
$this->assertCount(1, $metadata->getConstraints());
|
$this->assertCount(1, $metadata->getConstraints());
|
||||||
$this->assertInstanceOf(FormConstraint::class, $metadata->getConstraints()[0]);
|
$this->assertInstanceOf(FormConstraint::class, $metadata->getConstraints()[0]);
|
||||||
|
|
||||||
|
$this->assertSame(CascadingStrategy::NONE, $metadata->cascadingStrategy);
|
||||||
|
$this->assertSame(TraversalStrategy::IMPLICIT, $metadata->traversalStrategy);
|
||||||
$this->assertSame(CascadingStrategy::CASCADE, $metadata->getPropertyMetadata('children')[0]->cascadingStrategy);
|
$this->assertSame(CascadingStrategy::CASCADE, $metadata->getPropertyMetadata('children')[0]->cascadingStrategy);
|
||||||
$this->assertSame(TraversalStrategy::IMPLICIT, $metadata->getPropertyMetadata('children')[0]->traversalStrategy);
|
$this->assertSame(TraversalStrategy::IMPLICIT, $metadata->getPropertyMetadata('children')[0]->traversalStrategy);
|
||||||
}
|
}
|
||||||
@ -86,7 +92,57 @@ class ValidatorExtensionTest extends TestCase
|
|||||||
$this->assertFalse($form->get('baz')->isValid());
|
$this->assertFalse($form->get('baz')->isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createForm($type)
|
public function testFieldsValidateInSequence()
|
||||||
|
{
|
||||||
|
$allowEmptyString = property_exists(Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
|
||||||
|
|
||||||
|
$form = $this->createForm(FormType::class, null, [
|
||||||
|
'validation_groups' => new GroupSequence(['group1', 'group2']),
|
||||||
|
])
|
||||||
|
->add('foo', TextType::class, [
|
||||||
|
'constraints' => [new Length(['min' => 10, 'groups' => ['group1']] + $allowEmptyString)],
|
||||||
|
])
|
||||||
|
->add('bar', TextType::class, [
|
||||||
|
'constraints' => [new NotBlank(['groups' => ['group2']])],
|
||||||
|
])
|
||||||
|
;
|
||||||
|
|
||||||
|
$form->submit(['foo' => 'invalid', 'bar' => null]);
|
||||||
|
|
||||||
|
$errors = $form->getErrors(true);
|
||||||
|
|
||||||
|
$this->assertCount(1, $errors);
|
||||||
|
$this->assertInstanceOf(Length::class, $errors[0]->getCause()->getConstraint());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFieldsValidateInSequenceWithNestedGroupsArray()
|
||||||
|
{
|
||||||
|
$allowEmptyString = property_exists(Length::class, 'allowEmptyString') ? ['allowEmptyString' => true] : [];
|
||||||
|
|
||||||
|
$form = $this->createForm(FormType::class, null, [
|
||||||
|
'validation_groups' => new GroupSequence([['group1', 'group2'], 'group3']),
|
||||||
|
])
|
||||||
|
->add('foo', TextType::class, [
|
||||||
|
'constraints' => [new Length(['min' => 10, 'groups' => ['group1']] + $allowEmptyString)],
|
||||||
|
])
|
||||||
|
->add('bar', TextType::class, [
|
||||||
|
'constraints' => [new Length(['min' => 10, 'groups' => ['group2']] + $allowEmptyString)],
|
||||||
|
])
|
||||||
|
->add('baz', TextType::class, [
|
||||||
|
'constraints' => [new NotBlank(['groups' => ['group3']])],
|
||||||
|
])
|
||||||
|
;
|
||||||
|
|
||||||
|
$form->submit(['foo' => 'invalid', 'bar' => 'invalid', 'baz' => null]);
|
||||||
|
|
||||||
|
$errors = $form->getErrors(true);
|
||||||
|
|
||||||
|
$this->assertCount(2, $errors);
|
||||||
|
$this->assertInstanceOf(Length::class, $errors[0]->getCause()->getConstraint());
|
||||||
|
$this->assertInstanceOf(Length::class, $errors[1]->getCause()->getConstraint());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createForm($type, $data = null, array $options = [])
|
||||||
{
|
{
|
||||||
$validator = Validation::createValidatorBuilder()
|
$validator = Validation::createValidatorBuilder()
|
||||||
->setMetadataFactory(new LazyLoadingMetadataFactory(new StaticMethodLoader()))
|
->setMetadataFactory(new LazyLoadingMetadataFactory(new StaticMethodLoader()))
|
||||||
@ -95,7 +151,7 @@ class ValidatorExtensionTest extends TestCase
|
|||||||
$formFactoryBuilder->addExtension(new ValidatorExtension($validator));
|
$formFactoryBuilder->addExtension(new ValidatorExtension($validator));
|
||||||
$formFactory = $formFactoryBuilder->getFormFactory();
|
$formFactory = $formFactoryBuilder->getFormFactory();
|
||||||
|
|
||||||
return $formFactory->create($type);
|
return $formFactory->create($type, $data, $options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,15 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
|
|||||||
$this->prefetchData = $this->read($sessionId);
|
$this->prefetchData = $this->read($sessionId);
|
||||||
$this->prefetchId = $sessionId;
|
$this->prefetchId = $sessionId;
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID < 70317 || (70400 <= \PHP_VERSION_ID && \PHP_VERSION_ID < 70405)) {
|
||||||
|
// work around https://bugs.php.net/79413
|
||||||
|
foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) {
|
||||||
|
if (!isset($frame['class']) && isset($frame['function']) && \in_array($frame['function'], ['session_regenerate_id', 'session_create_id'], true)) {
|
||||||
|
return '' === $this->prefetchData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return '' !== $this->prefetchData;
|
return '' !== $this->prefetchData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ validateId
|
|||||||
read
|
read
|
||||||
doRead: abc|i:123;
|
doRead: abc|i:123;
|
||||||
read
|
read
|
||||||
|
doRead: abc|i:123;
|
||||||
|
|
||||||
write
|
write
|
||||||
doWrite: abc|i:123;
|
doWrite: abc|i:123;
|
||||||
|
@ -65,7 +65,7 @@ abstract class SMime
|
|||||||
protected function getStreamIterator($stream): iterable
|
protected function getStreamIterator($stream): iterable
|
||||||
{
|
{
|
||||||
while (!feof($stream)) {
|
while (!feof($stream)) {
|
||||||
yield fread($stream, 16372);
|
yield str_replace("\n", "\r\n", str_replace("\r\n", "\n", fread($stream, 16372)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,11 @@ class SMimeEncryptorTest extends SMimeTestCase
|
|||||||
private function assertMessageIsEncryptedProperly(Message $message, Message $originalMessage): void
|
private function assertMessageIsEncryptedProperly(Message $message, Message $originalMessage): void
|
||||||
{
|
{
|
||||||
$messageFile = $this->generateTmpFilename();
|
$messageFile = $this->generateTmpFilename();
|
||||||
file_put_contents($messageFile, $message->toString());
|
file_put_contents($messageFile, $messageString = $message->toString());
|
||||||
|
|
||||||
|
// Ensure the proper line-ending is used for compatibility with the RFC
|
||||||
|
$this->assertStringContainsString("\n\r", $messageString);
|
||||||
|
$this->assertStringNotContainsString("\n\n", $messageString);
|
||||||
|
|
||||||
$outputFile = $this->generateTmpFilename();
|
$outputFile = $this->generateTmpFilename();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user