Reputation: 1699
I have a Filter and FilterCollection object. The FilterCollection holds a collection of Filters, just like the name indicate. Now I need to validate everything, so I created a FilterType and FilterTypeCollection Forms. In the FilterCollectionType I have:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('filters', CollectionType::class, array(
'entry_type' => FilterType::class
));
}
And in the FilterCollection definition I have the following:
/**
* @var array
* @Assert\Valid()
*/
private $filters = [];
I created a paramConverter so I could convert elements from my request into FilterCollection ones. In the apply method I try to validate everything by using:
public function apply(Request $request, ParamConverter $configuration)
$filterCollection = new FilterCollection();
$form = $this->formFactory->create(
FilterTypeCollection::class,
$filterCollection
);
$form->submit($request->query->all());
if ($form->isSubmitted() && $form->isValid()) {
$request->attributes->set($configuration->getName(), $filterCollection);
return true;
} else {
throw new FormValidationException($form);
}
}
I was expecting that the validation not only validates the FilterCollection but also the Filters. But the validations I have in my Filter definition, are not working, even if I have validations that should fail, it still passes. I think the validator is not passing on the Filter elements.
Any idea on what might be happening?
Upvotes: 1
Views: 611
Reputation: 1536
I finally got it to work. Perhaps you made the same mistake as me, forgetting to add "data_class"
in the configureOptions
in the formType.
Anyway, here's the code that works (on fresh install of Symfony 3.3)
DefaultController.php
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Filter;
use AppBundle\Entity\FilterCollection;
use AppBundle\Form\FilterCollectionType;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* @Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
// add first filter, so we don't have to implement the collection javascript etc to test quickly
$collection = new FilterCollection();
$collection->filters[] = new Filter();
$form = $this->createForm(FilterCollectionType::class, $collection);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
echo "valid input"; // we don't want to see this ;)
}
}
// replace this example code with whatever you need
return $this->render('default/index.html.twig', [
'form' => $form->createView()
]);
}
}
Filter.php
<?php
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class Filter {
/**
* @var string
* @Assert\NotBlank()
* @Assert\Regex(pattern="/[0-9]+/")
*/
public $name;
}
FilterCollection.php
<?php
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class FilterCollection {
/**
* @var Filter[]
* @Assert\Valid()
*/
public $filters = [];
}
FilterType.php
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FilterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', TextType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\Filter'
]);
}
}
FilterCollectionType
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FilterCollectionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('filters', CollectionType::class, [
'entry_type' => FilterType::class,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\FilterCollection',
]);
}
public function getName()
{
return 'app_bundle_filter_collection_type';
}
}
Note: I didn't make a ParamConverter like you did, but that seems beside the point of the question. You can change the code to use a ParamConverter easily.
Upvotes: 1