2
votes

I installed Symfony3 and I'm trying to validate a formchild (entity child/not mapped fields) inside a normal form, with @Assert\Valid annotation. I couldn't do it so I tried the example from the Manual: http://symfony.com/doc/current/reference/constraints/Valid.html

This example, in Symfony 3, doesn't work (at least for me). This is where @Assert\Valid is used. How does Symfony knows in this case (example from manual) to valid the Address Entity and not any other Entity?

 /**
 * @Assert\Valid
 */
protected $address;

Has someone tried to test the example from the manual to see if it works?

Can someone please provide the working example from the manual? I don't know what I'm doing wrong..

This is my TestingController.php:

namespace WebsiteBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use WebsiteBundle\Entity\Author;
use WebsiteBundle\Form\Type\AuthorRegistrationType;

class TestingController extends Controller
{

    public function registerAccountAction(Request $request)
    {

        $author = new Author();

        $form = $this->createForm(AuthorRegistrationType::class, $author, array(
            'required' => false
        ));

        $form->handleRequest($request);

        if($form->isSubmitted() && $form->isValid()) {

           echo "It works";
        }


        return $this->render('TemplatesBundle:Default:testing_registration.html.twig', array(
            'form' => $form->createView(),
        ));
    }
}

The AuthorRegistrationType.php:

namespace WebsiteBundle\Form\Type;


use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class AuthorRegistrationType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add("firstname")
            ->add("lastname")
            ->add("zipcode", TextType::class, array('mapped' => false))
            ->add("street",  TextType::class, array('mapped' => false))
            ->add('save', SubmitType::class);
    }

}

Author Entity:

namespace WebsiteBundle\Entity;

use Symfony\Component\Validator\Constraints as Assert;

class Author
{
    /**
     * @Assert\NotBlank
     * @Assert\Length(min = 4)
     */
    protected $firstname;

    /**
     * @Assert\NotBlank
     */
    protected $lastname;

    /**
     * @Assert\Valid
     */
    protected $address;

    /**
     * @return mixed
     */
    public function getFirstname()
    {
        return $this->firstname;
    }

    /**
     * @param mixed $firstname
     */
    public function setFirstname($firstname)
    {
        $this->firstname = $firstname;
    }

    /**
     * @return mixed
     */
    public function getLastname()
    {
        return $this->lastname;
    }

    /**
     * @param mixed $lastname
     */
    public function setLastname($lastname)
    {
        $this->lastname = $lastname;
    }

    /**
     * @return mixed
     */
    public function getAddress()
    {
        return $this->address;
    }

    /**
     * @param mixed $address
     */
    public function setAddress(Address $address)
    {
        $this->address = $address;
    }


}

Address Entity:

namespace WebsiteBundle\Entity;

use Symfony\Component\Validator\Constraints as Assert;

class Address
{
    /**
     * @Assert\NotBlank()
     */
    protected $street;

    /**
     * @Assert\NotBlank
     * @Assert\Length(max = 5)
     */
    protected $zipCode;

    /**
     * @return mixed
     */
    public function getStreet()
    {
        return $this->street;
    }

    /**
     * @param mixed $street
     */
    public function setStreet($street)
    {
        $this->street = $street;
    }

    /**
     * @return mixed
     */
    public function getZipCode()
    {
        return $this->zipCode;
    }

    /**
     * @param mixed $zipCode
     */
    public function setZipCode($zipCode)
    {
        $this->zipCode = $zipCode;
    }


}

This is what I get now:

Firstname

     This value should not be blank.

Lastname

    This value should not be blank.

Street
Zipcode

So: the main Entity is validated, but the inherited one (Street/Zipcode) is "ignored"..

How can I validate (with this metod, not creating Custom Validation) the child entity?

Thanks

3

3 Answers

4
votes

The street and zipcode fields in your AuthorRegistrationTypeare not related to your Address entity. What is the reason you did it this way? I would create a separate form type for your Address entity:

namespace WebsiteBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class AddressType extends AbstractType
{
    protected function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('street', TextType::class)
            ->add('zipCode', TextType::class)
        ;
    }
}

Then you can embed this in your AuthorRegistrationType:

namespace WebsiteBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;

class AuthorRegistrationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add("firstname")
            ->add("lastname")
            ->add("address", AddressType::class)
            ->add('save', SubmitType::class);
    }
}    
1
votes

xabbuh is right:

I added in the controller the following:

$address = new Address();
$author->setAddress($address);

before

$form = $this->createForm(AuthorRegistrationType::class, $author, array(
        'required' => false
)); 

And in AddressType:

public function configureOptions(OptionsResolver $resolver)
{

    $resolver->setDefaults(array(
        'data_class' => 'WebsiteBundle\Entity\Address'
    ));
}

And it works!

0
votes

In your entity Author you have an attribute address, which is another entity Address. In my opinion this is called embedded entity, not inherited. However I'm not a native English speaker, so I cannot guarantee.

The issue is in your entity Author:

/**
 * @Assert\Valid
 */
protected $address;

This will validate the field itself, but not the fields street and zipCode from the entity Address. To achieve that, you should tell the validation to traverse to the entity Address and look up for the validations in there:

/**
 * @Assert\Valid(
 *    traverse = true
 * )
 */
protected $address;

This should do the job.

EDIT:

I couldn't see the relation between these two entities immediately in your examples. Now I see that Author can have only one Address. That means the above suggested code won't do the work for you. It is necessary only if you have a relation where an Author has a field address which is a collection, i.e one author can have many addresses.