DonCallisto
DonCallisto

Reputation: 29912

symfony2 form validation and constraint

I just created a form that have to "catch" data for transfer them to a "User Object" and persist it to DB.

In order, for do that, i follow those steps:

  1. Create a User Object
  2. Create a UserRepository for make it persistent and fetch it (throught Entity Manager)
  3. Create a class that "map" the form
  4. Create a route and a template for render the whole thing

So step over the first two of those and let's see together the third step

<?php
namespace Sestante\UserBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\MinLength;
use Symfony\Component\Validator\Constraints\Collection;

class AddUserType extends AbstractType
{
    public function BuildForm(FormBuilder $builder, array $options)
    {
        $builder->add('username','text')
                ->add('email','email')
                ->add('id','hidden')
                ->add('password','text')
                ;
    }

    public function getName()
    {
        return 'AddUser';
    }

This is part of the class that i've created for "form handle".
Obviously i want to add some kind of validation to my form, and following symfony2 book i've done this

public function getDefaultOptions(array $options)
{
    $collectionConstraint = new Collection(array(
        'username'=> new MinLength(4),
        'email'=>new Email(array('message'=>'invalid email address')),
    ));

    return array(
        'data_class' => 'Sestante\UserBundle\Entity\User',
        'validation_constraint' => $collectionConstraint
    );
}

As far i understood, constraints will be checked on the $form->bindRequest(...) or ->bind(...) calls.

So, into my controller, i've done this

public function insertAction(Request $request)
{
   if($request->getMethod() == 'POST'){
       $em = $this->getDoctrine()->getEntityManager();
       $user = $em->getRepository('SestanteUserBundle:User');
       $userObj = new User();
       $userObj->setSalt('prova');
       $parameters = $request->request->get('AddUser');
       $parameters['password'] = sha1($parameters['password']);
       $userObj->setGroups($em->getRepository('SestanteUserBundle:Groups')->find(3));
       $form = $this->createForm(new AddUserType(), $userObj);
       $logger = $this->get('logger');
       $logger->info('PROVA: '.gettype($parameters));
       $form->bind($parameters); /* al posto che fare un bind della form, faccio un bind normale con i parametri presi dalla post e modificati
                                 vedi la password che deve subire uno sha1 */
       $em->persist($userObj);
       $em->flush();
       return $this->redirect($this->generateUrl('SestanteUserBundle_homepage'));
   }

But as i submit the form, i'll have to struggle with this error

Expected argument of type array or Traversable and ArrayAccess, object given

The strangest thing is that the only two object involved in this operation (bind argument and constraint collections) are of requested type. So i don't know how to overtake this.
Any idea?

Upvotes: 2

Views: 5598

Answers (1)

Olivier Dolbeau
Olivier Dolbeau

Reputation: 1204

Try with something like this:

public function insertAction(Request $request)
{
    // First: Create you're object with only what you need
    $userObj = new User();

    // Then, build you're form
    $form = $this->createForm(new AddUserType(), $userObj);

    // Form submitted?
    if ($request->getMethod() == 'POST') {
        $request = $this->getRequest();
        $em = $this->getDoctrine()->getEntityManager();

        // Bind $request now !
        $form->bindRequest($request);

        // Your object is updated (not saved, ofc). You can now do what you want.
        $userObj->setPassword(sha1($user->getPassword());
        $userObj->setGroups($em->getRepository('SestanteUserBundle:Groups')->find(3));

        // Finish, save user
        $em->persist($userObj);
        $em->flush();

        return $this->redirect($this->generateUrl('SestanteUserBundle_homepage'));
    }
}

Some other things:

  • you don't need to put the id field in your form.
  • you should probably take a look at the sf2 security. It's not a good idea to manually encode password in a controller.

Edit:

You got this Exception because you can't use the validation_constraint option in a form which deal with an object.

This option can only be used with an array of data.

Upvotes: 3

Related Questions