2

I have a Parents form embedded into another form Student containing the data of the parents of a student. I need to validate the embedded form, because in my code just makes the validation of another form.

StudentType.php

  //...
  ->add('responsible1', new ParentsType(),array('label' => 'Mother'))
  ->add('responsible2', new ParentsType(),array('label'=> 'Father'))

 /**
 * @param OptionsResolverInterface $resolver
 */
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'BackendBundle\Entity\Student'
    ));
}

Entity Parents

 //...
 /**
 * @ORM\OneToMany(targetEntity="Student", mappedBy="$responsible1")
 * @ORM\OneToMany(targetEntity="Student", mappedBy="$responsible2")
 */
 private $students;

Entity Student

 //...
 /**
 * 
 * @ORM\ManyToOne(targetEntity="Parents", inversedBy="students", cascade={"persist"})
 */
 private $responsible1;

/**
 * 
 * @ORM\ManyToOne(targetEntity="Parents", inversedBy="students", cascade={"persist"})
 */
 private $responsible2;

Using the following code in the controller I got the name and the error message of all invalid fields in the main form (Student), but I get get errors embedded forms (Parents), just get the name of the object (responsible1 or responsible2) and the message I get [object Object].

StudentController.php

protected function getErrorMessages(\Symfony\Component\Form\Form $form) 
{
    $errors = array();

    foreach ($form->getErrors() as $key => $error) {
        $errors[] = $error->getMessage();
    }

    foreach ($form->all() as $child) {
        if (!$child->isValid()) {
            $errors[$child->getName()] = $this->getErrorMessages($child);
        }
    }

    return $errors;
}
/**
 * Creates a new Student entity.
 *
 */
public function createAction(Request $request)
{
// if request is XmlHttpRequest (AJAX) but not a POSt, throw an exception
if ($request->isXmlHttpRequest() && !$request->isMethod('POST')) {
    throw new HttpException('XMLHttpRequests/AJAX calls must be POSTed');
}

    $entity = new Student();
    $form = $this->createCreateForm($entity);
    $form->handleRequest($request);

    if ($form->isValid()) {

        $em = $this->getDoctrine()->getManager();
        $em->persist($entity);
        $em->flush();

        if ($request->isXmlHttpRequest()) {
        return new JsonResponse(array('message' => 'Success!'), 200);
    }

        return $this->redirect($this->generateUrl('student_show', array('id' => $entity->getId())));
    }

     if ($request->isMethod('POST')) {
                    return new JsonResponse(array(
        'result' => 0,
        'message' => 'Invalid form',
        'data' => $this->getErrorMessages($form)),400);
    }

    return $this->render('BackendBundle:Student:new.html.twig', array(
        'entity' => $entity,
        'form'   => $form->createView(),
    ));
}

I tried the above code with the function getErrorsAsString() for errors in a string and so if they appear all, so I guess I'll have to add something in the above code to validate objects when "responsible1" or "responsible2" validate all fields.

I need to get all those errors are invalid fields on both forms.I read something to add 'cascade_validation' => true , validation_group or @Assert\Valid() by the code, but I tried and I failed to get it. If someone can explain to me a little worth those, I thank you because I'm new to all this.

3
  • are you looking for a way to flattern error messages including nested forms ? Commented Dec 6, 2015 at 21:45
  • Hi @b.b3rn4rd, what I need is to validate a form and return with a JsonResponse an Ajax call and then indicate invalid form fields without refreshing the screen. This was a solution but I can not get the errors of the embedded forms. Commented Dec 6, 2015 at 21:53
  • makes sense, I was doing similar thing for ajax validation, posted a solution that works for me Commented Dec 6, 2015 at 22:00

1 Answer 1

2

Following example flatterns form and subform errors into assoc array, let me know if this is what you are trying to achieve

<?php
namespace Example\Bundle\UtilityBundle\Form;
use Symfony\Component\Form\Form;
class FormErrors
{
    public function getArray(Form $form, $style = 'KO')
    {
        $method = sprintf('get%sErrors', $style);

        $messages = $this->$method($form->all());

        return $messages;
    }

    private function getKOErrors(Form $children)
    {
        $errors = array();

        /* @var $child \Symfony\Component\Form\Form */
        foreach ($children as $child) {
            $type = $child->getConfig()->getType()->getName();
            if ($child->count()  && ($type !== 'choice')) {
                $childErrors = $this->getKOErrors($child->all());
                if (sizeof($childErrors)) {
                    $errors = array_merge($errors, $childErrors);
                }
            } else {
                if (!$child->isValid()) {
                    // I need only one error message per field 
                    $errors[$child->getName()] = $child->getErrors()->current()->getMessage();
                }
            }
        }

        return $errors;
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Hi @b.b3rn4rd ,With your code I could get errors of the form was missing, but in my case, the form is embedded in the main twice. For me understand I have a student registration form and within me appears a registration form from the father and other data of the mother (both are of the same type). And what if I get any field is invalid both forms are the first fields.You need to somehow differentiate the errors obtained, for example responsible1_name or responsible2_name. I hope I explained well and thank you for your answer.
@Joseph, just add a second param $name to getKOErrors(Form $children, $name) and concatenate $errors[$name.'_'.$child->getName() ] and don't forget to pass it ->getName() when calling
now everything works perfect, I believe that what I needed was to differentiate them, thank you very much, helped me a great help.
No worries, glad it helped

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.