Symfony2: วิธีรับข้อผิดพลาดในการตรวจสอบแบบฟอร์มหลังจากผูกคำขอเข้ากับแบบฟอร์ม


110

นี่คือsaveActionรหัสของฉัน(ที่แบบฟอร์มส่งข้อมูลไปยัง)

public function saveAction()
{
    $user = OBUser();

    $form = $this->createForm(new OBUserType(), $user);

    if ($this->request->getMethod() == 'POST')
    {
        $form->bindRequest($this->request);
        if ($form->isValid())
            return $this->redirect($this->generateUrl('success_page'));
        else
            return $this->redirect($this->generateUrl('registration_form'));
    } else
        return new Response();
}

คำถามของฉันคือฉันจะได้รับข้อผิดพลาดหาก$form->isValid()ส่งคืนได้falseอย่างไร?

คำตอบ:


117

คุณมีสองวิธีที่ทำได้:

  • อย่าเปลี่ยนเส้นทางผู้ใช้เมื่อเกิดข้อผิดพลาดและแสดง{{ form_errors(form) }}ภายในไฟล์เทมเพลต
  • เข้าถึงอาร์เรย์ข้อผิดพลาดเป็น $form->getErrors()

22
ฉันทำสิ่งที่สองที่คุณแนะนำ แต่ form-> getErrors () ส่งคืนอาร์เรย์ว่าง
putolaruan

2
ฉันทำแบบแรกด้วย (w / php template <? php echo $ view ['form'] -> error ($ form)?>) แต่ก็ยังว่างอยู่!
putolaruan

59
@mives คุณต้องตั้งค่าerror_bubblingเป็น true ในประเภทฟอร์มของคุณโดยการตั้งค่าตัวเลือกสำหรับแต่ละฟิลด์อย่างชัดเจน
kgilden

5
หากคุณใช้โปรแกรมตรวจสอบที่กำหนดเอง Symfony จะไม่ส่งคืนข้อผิดพลาดที่สร้างขึ้นโดยตัวตรวจสอบความถูกต้องเหล่านั้นใน $ form-> getErrors ()
Jay Sheth

13
คุณสามารถ$form->getErrors(true)รวมข้อผิดพลาดของแบบฟอร์มลูกได้เช่นกัน
คริส

103

Symfony 2.3 / 2.4:

ฟังก์ชั่นนี้เป็นข้อผิดพลาดทั้งหมด รายการในแบบฟอร์มเช่น "โทเค็น CSRF ไม่ถูกต้องโปรดลองส่งแบบฟอร์มอีกครั้ง" เช่นเดียวกับข้อผิดพลาดเพิ่มเติมในแบบฟอร์มเด็กที่ไม่มีข้อผิดพลาดเกิดขึ้น

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

    foreach ($form->getErrors() as $key => $error) {
        if ($form->isRoot()) {
            $errors['#'][] = $error->getMessage();
        } else {
            $errors[] = $error->getMessage();
        }
    }

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

    return $errors;
}

หากต้องการรับข้อผิดพลาดทั้งหมดเป็นสตริง:

$string = var_export($this->getErrorMessages($form), true);

Symfony 2.5 / 3.0:

$string = (string) $form->getErrors(true, false);

เอกสาร:
https://github.com/symfony/symfony/blob/master/UPGRADE-2.5.md#form https://github.com/symfony/symfony/blob/master/UPGRADE-3.0.md#form (ที่ ด้านล่าง: The method Form::getErrorsAsString() was removed)


1
ดูเหมือนว่าคำตอบที่ถูกต้องที่สุดสำหรับ Symfony 2.4 ปัจจุบัน
Slava Fomin II

@Flip ทำงานได้อย่างสมบูรณ์บน 2.5
iarroyo

1
คำตอบที่ดี แต่$errors[$child->getName()] = $this->getErrorMessages($child);กำลังส่งข้อยกเว้นเนื่องจากgetErrorMessagesขาดหายไปจากส่วนประกอบSymfony \ Bundle \ FrameworkBundle \ Controller \ Controller ดังนั้นฉันจึงแทนที่ด้วย$form_errors[$child->getName()] = $child->getErrorsAsString();
Ahad Ali

3
@AhadAli เป็นฟังก์ชันแบบเรียกซ้ำดังนั้นเมื่อคุณใส่ข้อมูลโค้ดในคลาสที่คุณต้องการฟังก์ชันนี้ก็จะสามารถเรียกตัวเองได้ "การแก้ไข" ของคุณจะป้องกันไม่ให้คุณเข้าถึงแบบฟอร์มที่ซ้อนกัน มันใช้ได้กับคนอื่น 37 คนมันก็น่าจะใช้ได้เหมือนกัน;)
พลิก

@Flip อาขอโทษที่ฉันไม่ดีฉันแค่มอง$this->getErrorMessages()และคิดว่ามันถูกเรียกโดยตรงภายในคอนโทรลเลอร์และเป็นส่วนหนึ่งของ Symfony api
Ahad Ali

47

ด้านล่างนี้เป็นวิธีแก้ปัญหาที่เหมาะกับฉัน ฟังก์ชันนี้อยู่ในคอนโทรลเลอร์และจะส่งคืนอาร์เรย์ที่มีโครงสร้างของข้อความแสดงข้อผิดพลาดทั้งหมดและฟิลด์ที่ทำให้เกิด

Symfony 2.0:

private function getErrorMessages(\Symfony\Component\Form\Form $form) {
    $errors = array();
    foreach ($form->getErrors() as $key => $error) {
        $template = $error->getMessageTemplate();
        $parameters = $error->getMessageParameters();

        foreach($parameters as $var => $value){
            $template = str_replace($var, $value, $template);
        }

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

    return $errors;
}

Symfony 2.1 และใหม่กว่า:

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

    if ($form->hasChildren()) {
        foreach ($form->getChildren() as $child) {
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }
    } else {
        foreach ($form->getErrors() as $key => $error) {
            $errors[] = $error->getMessage();
        }   
    }

    return $errors;
}

5
ปรับปรุงgist.github.com/2011671แต่ยังไม่ใช่สิ่งที่ฉันต้องการ ฉันต้องการให้คีย์อาร์เรย์เป็นชื่อฟิลด์ แต่ไม่ใช่
umpirsky

9
@SalmanPK Twig ไม่ได้อ้างอิงที่ใดก็ได้ในโค้ดด้านบน ฉันไม่เชื่อว่าฉันเข้าใจความคิดเห็นของคุณ
Icode4food

1
นี่คือการแก้ไขสำหรับส่วนสำคัญก่อนหน้านี้ซึ่งทำงานภายใต้ Symfony 2.1.7 gist.github.com/WishCow/5101428
K. Norbert

มันดูเหมือนว่ามีการพิมพ์ผิด$this->getFormErrorsควรจะเป็น$this->getErrorMessagesในตัวอย่างของคุณใน Symfony2.1
มิก

@umpirsky เพื่อให้ได้ชื่อฟิลด์ฉันได้สิ่งนี้: $ child-> getConfig () -> getOptions () ['label'] พาฉันไปหาตลอดไป ...
jsgoupil

35

ใช้ Validator เพื่อรับข้อผิดพลาดสำหรับเอนทิตีเฉพาะ

if( $form->isValid() )
{
    // ...
}
else
{
    // get a ConstraintViolationList
    $errors = $this->get('validator')->validate( $user );

    $result = '';

    // iterate on it
    foreach( $errors as $error )
    {
        // Do stuff with:
        //   $error->getPropertyPath() : the field that caused the error
        //   $error->getMessage() : the error message
    }
}

การอ้างอิง API:


ขอบคุณสิ่งที่ฉันต้องการ +1
Phill Pafford

4
ฉันไม่แน่ใจว่าเป็นแนวทางที่ดีในการตรวจสอบความถูกต้องของแต่ละเอนทิตีแยกกัน จะเกิดอะไรขึ้นถ้าคุณมีรูปแบบลำดับชั้นที่ซับซ้อน? ปัญหาที่สองคือการตรวจสอบความถูกต้องเกิดขึ้นสองครั้ง
Slava Fomin II

3
@SlavaFominII - "ปัญหาที่สองคือการตรวจสอบความถูกต้องเกิดขึ้นสองครั้ง" - จุดดีไม่มีอะไรได้รับการรีเฟรช! รายการข้อผิดพลาดเดียวกันหลังจาก!
BentCoder

20

เพื่อให้ได้ข้อความที่ถูกต้อง (แปลได้) ปัจจุบันใช้ SF 2.6.3 นี่คือฟังก์ชั่นสุดท้ายของฉัน (เนื่องจากดูเหมือนว่าจะไม่มีข้อใดใช้งานได้อีกต่อไป):

 private function getErrorMessages(\Symfony\Component\Form\Form $form) {      
    $errors = array();
    foreach ($form->getErrors(true, false) as $error) {
        // My personnal need was to get translatable messages
        // $errors[] = $this->trans($error->current()->getMessage());
        $errors[] = $error->current()->getMessage();
    }

    return $errors;
}

เป็นรูปแบบที่ :: getErrors () วิธีการในขณะนี้จะส่งกลับตัวอย่างของFormErrorIteratorเว้นแต่คุณจะสลับอาร์กิวเมนต์ที่สอง ($ เรียบ) ไปจริง (จากนั้นจะส่งคืนอินสแตนซ์FormErrorและคุณจะต้องเรียกใช้เมธอด getMessage () โดยตรงโดยไม่ใช้เมธอด current ():

 private function getErrorMessages(\Symfony\Component\Form\Form $form) {      
    $errors = array();
    foreach ($form->getErrors(true, true) as $error) {
        // My personnal need was to get translatable messages
        // $errors[] = $this->trans($error->getMessage());
        $errors[] = $error->getMessage();
    }

    return $errors;
}

)

สิ่งที่สำคัญที่สุดคือการตั้งค่าอาร์กิวเมนต์แรกเป็นจริงเพื่อให้ได้ข้อผิดพลาด การปล่อยให้อาร์กิวเมนต์ที่สอง ($ flatten) เป็นค่าเริ่มต้น ( true ) จะส่งคืนอินสแตนซ์FormErrorในขณะที่มันจะส่งคืนอินสแตนซ์FormErrorIteratorเมื่อตั้งค่าเป็นเท็จ


ดีที่ใช้ของเดียวกัน
อินทรีย์ที่เสียหาย

ไม่ใช่เหรอ :) @KidBinary
Cedo

สวยมากเพื่อน :)
Damaged Organic

ตัวเลือกที่ดีกว่าคือ: $ error = array_map (function ($ item) {return $ item-> current () -> getMessage ();}, $ campaignForm-> getErrors (true, false));
Enrique Quero

ทางออกที่ดีสำหรับ Symfony 2.7
Yann Chabot

16

สำหรับข้อความแฟลชของฉันฉันมีความสุข $form->getErrorsAsString()

แก้ไข (จาก Benji_X80): สำหรับการใช้งาน SF3 $form->getErrors(true, false);


3
ฉันรู้ว่ามันเป็นคำตอบเก่า แต่สำหรับการอ้างอิงในอนาคต: This method should only be used to help debug a form.(ที่มา )
cheesemacfly

getErrorsAsString () เลิกใช้แล้วใน 3.0 ให้ใช้: $ form-> getErrors (true, false);
Benji_X80

15

ฟังก์ชันสำหรับ symfony 2.1 และใหม่กว่าโดยไม่มีฟังก์ชันที่เลิกใช้งาน:

/**
 * @param \Symfony\Component\Form\Form $form
 *
 * @return array
 */
private function getErrorMessages(\Symfony\Component\Form\Form $form)
{
    $errors = array();

    if ($form->count() > 0) {
        foreach ($form->all() as $child) {
            /**
             * @var \Symfony\Component\Form\Form $child
             */
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }
    } else {
        /**
         * @var \Symfony\Component\Form\FormError $error
         */
        foreach ($form->getErrors() as $key => $error) {
            $errors[] = $error->getMessage();
        }
    }

    return $errors;
}

ฉันกำลังจะโพสต์คำตอบใหม่สำหรับโพสต์นี้ แต่ดูเหมือนว่าคุณจะเอาชนะฉันได้ ฉันต้องดูซอร์สโค้ดเพื่อหาสาเหตุว่าทำไมไม่พบการเรียกเมธอด
Dr.Knowitall

ฉันสังเกตว่าสิ่งนี้ไม่ได้ดึงข้อผิดพลาดจากรายการที่มีข้อผิดพลาดในการตั้งค่าเป็นจริง SF2.4
kinghfb

@stwe วัตถุประสงค์ของIFคำสั่งแรกคืออะไร? เหตุใดจึงเป็นเอกสิทธิ์เฉพาะบุคคล เท่าที่ฉันเห็น: แบบฟอร์มอาจมีข้อผิดพลาดของตัวเองเช่นเดียวกับเด็ก ๆ
Slava Fomin II

4

ข้อความแสดงข้อผิดพลาดของฟอร์มที่แปลแล้ว (Symfony2.1)

ฉันพยายามอย่างมากในการค้นหาข้อมูลนี้ดังนั้นฉันคิดว่ามันคุ้มค่าที่จะเพิ่มหมายเหตุเกี่ยวกับการแปลข้อผิดพลาดแบบฟอร์ม

@Icode4foodคำตอบจะแสดงข้อผิดพลาดทั้งหมดของแบบฟอร์ม อย่างไรก็ตามอาร์เรย์ที่ส่งคืนไม่ได้คำนึงถึงการทำให้เป็นพหูพจน์ของข้อความหรือการแปลแปล

คุณสามารถปรับเปลี่ยน foreach loop ของ@Icode4foodคำตอบให้มีคำสั่งผสม:

  • รับข้อผิดพลาดทั้งหมดของรูปแบบเฉพาะ
  • ส่งคืนข้อผิดพลาดที่แปล
  • คำนึงถึงการเป็นพหูพจน์หากจำเป็น

นี่คือ:

foreach ($form->getErrors() as $key => $error) {

   //If the message requires pluralization
    if($error->getMessagePluralization() !== null) {
        $errors[] = $this->container->get('translator')->transChoice(
            $error->getMessage(), 
            $error->getMessagePluralization(), 
            $error->getMessageParameters(), 
            'validators'
            );
    } 
    //Otherwise, we do a classic translation
    else {
        $errors[] = $this->container->get('translator')->trans(
            $error->getMessage(), 
            array(), 
            'validators'
            );
    }
}

คำตอบนี้ถูกรวบรวมจาก 3 โพสต์ที่แตกต่างกัน:


เพิ่งลองใช้เวอร์ชันของคุณและมันก็ใช้งานFatal Error: Call to undefined method Symfony\Component\Form\FormError::getMessagePluralization()ได้ ฉันสงสัยว่านี่ใช้สำหรับ Symfony 2.1 เท่านั้น?
Czar Pino

4

SYMFONY 3.X

วิธีอื่น ๆ ของ SF 3.X ที่ให้ไว้ที่นี่ไม่ได้ผลสำหรับฉันเพราะฉันสามารถส่งข้อมูลเปล่าไปยังแบบฟอร์มได้ (แต่ฉันมีข้อ จำกัด ของ NotNull / NotBlanck) ในกรณีนี้สตริงข้อผิดพลาดจะมีลักษณะดังนี้:

string(282) "ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be null.
name:
    ERROR: This value should not be blank.
"

ซึ่งไม่ค่อยมีประโยชน์ ฉันจึงทำสิ่งนี้:

public function buildErrorArray(FormInterface $form)
{
    $errors = [];

    foreach ($form->all() as $child) {
        $errors = array_merge(
            $errors,
            $this->buildErrorArray($child)
        );
    }

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

    return $errors;
}

ซึ่งจะกลับมา:

array(7) {
  ["data.name"]=>
  string(31) "This value should not be blank."
  ["data.street"]=>
  string(31) "This value should not be blank."
  ["data.zipCode"]=>
  string(31) "This value should not be blank."
  ["data.city"]=>
  string(31) "This value should not be blank."
  ["data.state"]=>
  string(31) "This value should not be blank."
  ["data.countryCode"]=>
  string(31) "This value should not be blank."
  ["data.organization"]=>
  string(30) "This value should not be null."
}

3

คุณยังสามารถใช้บริการตรวจสอบความถูกต้องเพื่อรับการละเมิดข้อ จำกัด :

$errors = $this->get('validator')->validate($user);

6
สิ่งนี้จะตรวจสอบความถูกต้องของวัตถุ แต่ไม่ใช่แบบฟอร์ม ตัวอย่างเช่นหากโทเค็น CRSF เป็นสาเหตุของข้อผิดพลาดข้อความจะไม่รวมอยู่ด้วย
Icode4food

3

ข้อความแสดงข้อผิดพลาดแบบฟอร์มที่แปลแล้ว (Symfony2.3)

เวอร์ชันของฉันในการแก้ปัญหา:

/src/Acme/MyBundle/Resources/config/services.yml

services:
    form_errors:
        class: Acme\MyBundle\Form\FormErrors

/src/Acme/MyBundle/Form/FormErrors.php

<?php
namespace Acme\MyBundle\Form;

class FormErrors
{
    public function getArray(\Symfony\Component\Form\Form $form)
    {
        return $this->getErrors($form);
    }

    private function getErrors($form)
    {
        $errors = array();

        if ($form instanceof \Symfony\Component\Form\Form) {

            // соберем ошибки элемента
            foreach ($form->getErrors() as $error) {

                $errors[] = $error->getMessage();
            }

            // пробежимся под дочерним элементам
            foreach ($form->all() as $key => $child) {
                /** @var $child \Symfony\Component\Form\Form */
                if ($err = $this->getErrors($child)) {
                    $errors[$key] = $err;
                }
            }
        }

        return $errors;
    }
}

/src/Acme/MyBundle/Controller/DefaultController.php

$form = $this->createFormBuilder($entity)->getForm();
$form_errors = $this->get('form_errors')->getArray($form);
return new JsonResponse($form_errors);

ใน Symfony 2.5คุณสามารถรับข้อผิดพลาดของฟิลด์ทั้งหมดได้ง่ายมาก:

    $errors = array();
    foreach ($form as $fieldName => $formField) {
        foreach ($formField->getErrors(true) as $error) {
            $errors[$fieldName] = $error->getMessage();
        }
    }

3

สำหรับSymfony 3.2ขึ้นไปให้ใช้สิ่งนี้

public function buildErrorArray(FormInterface $form)
{
    $errors = array();

    foreach ($form->getErrors() as $key => $error) {
        if ($form->isRoot()) {
            $errors['#'][] = $error->getMessage();
        } else {
            $errors[] = $error->getMessage();
        }
    }

    foreach ($form->all() as $child) {
        if (!$child->isValid()) {
            $errors[$child->getName()] = (string) $child->getErrors(true, false);
        }
    }
    return $errors;
}

ใช้str_replaceหากคุณต้องการกำจัดข้อความ ' Error: ' ที่น่ารำคาญในข้อความอธิบายข้อผิดพลาดแต่ละข้อความ

$errors[$child->getName()] = str_replace('ERROR:', '', (string) $child->getErrors(true, false));

2

หากคุณกำลังใช้เครื่องมือตรวจสอบที่กำหนดเอง Symfony $form->getErrors()ไม่กลับข้อผิดพลาดที่เกิดจากเครื่องมือตรวจสอบผู้ที่อยู่ใน$form->getErrorsAsString()จะส่งคืนข้อผิดพลาดทั้งหมดที่คุณต้องการ แต่ผลลัพธ์ของมันถูกจัดรูปแบบเป็นสตริงไม่ใช่อาร์เรย์

วิธีที่คุณใช้เพื่อรับข้อผิดพลาดทั้งหมด (ไม่ว่าจะมาจากที่ใด) ขึ้นอยู่กับเวอร์ชันของ Symfony ที่คุณใช้

โซลูชันที่แนะนำส่วนใหญ่เกี่ยวข้องกับการสร้างฟังก์ชันเรียกซ้ำที่สแกนฟอร์มย่อยทั้งหมดและแยกข้อผิดพลาดที่เกี่ยวข้องออกเป็นอาร์เรย์เดียว Symfony 2.3 ไม่มี$form->hasChildren()ฟังก์ชั่น แต่มี$form->all().

นี่คือคลาสตัวช่วยสำหรับ Symfony 2.3 ซึ่งคุณสามารถใช้เพื่อดึงข้อผิดพลาดทั้งหมดจากรูปแบบใดก็ได้ (มันขึ้นอยู่กับรหัสจากความคิดเห็นโดย yapro ในตั๋วข้อผิดพลาดที่เกี่ยวข้องในบัญชี github ของ Symfony)

namespace MyApp\FormBundle\Helpers;

use Symfony\Component\Form\Form;

class FormErrorHelper
{
    /**
     * Work-around for bug where Symfony (2.3) does not return errors from custom validaters,
     * when you call $form->getErrors().
     * Based on code submitted in a comment here by yapro:
     * https://github.com/symfony/symfony/issues/7205
     *
     * @param Form $form
     * @return array Associative array of all errors
     */
    public function getFormErrors($form)
    {
        $errors = array();

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

            foreach ($form->all() as $key => $child) {
                /** @var $child Form */
                if ($err = $this->getFormErrors($child)) {
                    $errors[$key] = $err;
                }
            }
        }

        return $errors;
    }
}

รหัสโทร:

namespace MyApp\ABCBundle\Controller;

use MyApp\FormBundle\Helpers;

class MyController extends Controller
{
    public function XYZAction()
    {
        // Create form.

        if (!$form->isValid()) {
            $formErrorHelper = new FormErrorHelper();
            $formErrors = $formErrorHelper->getFormErrors($form);

            // Set error array into twig template here.
        }
    }

}

2

จากคำตอบของ @Jay Seth ฉันได้สร้างคลาส FormErrors โดยเฉพาะสำหรับ Ajax Forms:

// src/AppBundle/Form/FormErrors.php
namespace AppBundle\Form;

class FormErrors
{

    /**
     * @param \Symfony\Component\Form\Form $form
     *
     * @return array $errors
     */
    public function getArray(\Symfony\Component\Form\Form $form)
    {
        return $this->getErrors($form, $form->getName());
    }

    /**
     * @param \Symfony\Component\Form\Form $baseForm
     * @param \Symfony\Component\Form\Form $baseFormName
     *
     * @return array $errors
     */
    private function getErrors($baseForm, $baseFormName) {
        $errors = array();
        if ($baseForm instanceof \Symfony\Component\Form\Form) {
            foreach($baseForm->getErrors() as $error) {
                $errors[] = array(
                    "mess"      => $error->getMessage(),
                    "key"       => $baseFormName
                );
            }

            foreach ($baseForm->all() as $key => $child) {
                if(($child instanceof \Symfony\Component\Form\Form)) {
                    $cErrors = $this->getErrors($child, $baseFormName . "_" . $child->getName());
                    $errors = array_merge($errors, $cErrors);
                }
            }
        }
        return $errors;
    }
}

การใช้งาน (เช่นในการกระทำของคุณ):

$errors = $this->get('form_errors')->getArray($form);

เวอร์ชัน Symfony: 2.8.4

ตัวอย่างการตอบสนอง JSON:

{
    "success": false,
    "errors": [{
        "mess": "error_message",
        "key": "RegistrationForm_user_firstname"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_lastname"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_email"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_zipCode"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_password_password"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_terms"
    }, {
        "mess": "error_message2",
        "key": "RegistrationForm_terms"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_marketing"
    }, {
        "mess": "error_message2",
        "key": "RegistrationForm_marketing"
    }]
}

ออบเจ็กต์ข้อผิดพลาดมีช่อง "คีย์" ซึ่งเป็นรหัสขององค์ประกอบ DOM อินพุตดังนั้นคุณสามารถเติมข้อความแสดงข้อผิดพลาดได้อย่างง่ายดาย

หากคุณมีรูปแบบเด็กภายในแม่ไม่ลืมที่จะเพิ่มตัวเลือกภายในของแบบฟอร์มหลักcascade_validationsetDefaults


1

สำหรับ Symfony 2.1 เป็นต้นไปเพื่อใช้กับการแสดงข้อผิดพลาดของ Twig ฉันได้เปลี่ยนฟังก์ชันเพื่อเพิ่ม FormError แทนที่จะเพียงแค่ดึงข้อมูลออกมาวิธีนี้คุณจะสามารถควบคุมข้อผิดพลาดได้มากขึ้นและไม่ต้องใช้ error_bubbling ในการป้อนข้อมูลแต่ละรายการ หากคุณไม่ได้ตั้งค่าในลักษณะด้านล่างนี้ {{form_errors (form)}} จะว่างเปล่า:

/**
 * @param \Symfony\Component\Form\Form $form
 *
 * @return void
 */
private function setErrorMessages(\Symfony\Component\Form\Form $form) {      

    if ($form->count() > 0) {
        foreach ($form->all() as $child) {
            if (!$child->isValid()) {
                if( isset($this->getErrorMessages($child)[0]) ) {
                    $error = new FormError( $this->getErrorMessages($child)[0] );
                    $form->addError($error);
                }
            }
        }
    }

}


1

ฉันคิดวิธีแก้ปัญหานี้ขึ้นมา มันทำงานที่มั่นคงกับล่าสุดSymfony 2.4

ฉันจะพยายามให้คำอธิบาย

ใช้ตัวตรวจสอบความถูกต้องแยกต่างหาก

ฉันคิดว่าเป็นความคิดที่ดีที่จะใช้การตรวจสอบความถูกต้องแยกต่างหากเพื่อตรวจสอบเอนทิตีและส่งคืนข้อความการละเมิดข้อ จำกัด เช่นที่นักเขียนคนอื่นแนะนำ

  1. คุณจะต้องตรวจสอบความถูกต้องของเอนทิตีทั้งหมดด้วยตนเองระบุกลุ่มการตรวจสอบความถูกต้อง ฯลฯ ฯลฯ ด้วยรูปแบบลำดับชั้นที่ซับซ้อนจะไม่สามารถใช้งานได้จริงและจะหลุดออกจากมืออย่างรวดเร็ว

  2. ด้วยวิธีนี้คุณจะตรวจสอบความถูกต้องของแบบฟอร์มสองครั้ง: ครั้งเดียวกับแบบฟอร์มและอีกครั้งด้วยตัวตรวจสอบความถูกต้องแยกต่างหาก นี่เป็นความคิดที่ไม่ดีจากมุมมองด้านประสิทธิภาพ

ฉันขอแนะนำให้ทำซ้ำประเภทฟอร์มซ้ำกับเด็กเพื่อรวบรวมข้อความแสดงข้อผิดพลาด

ใช้วิธีการที่แนะนำพร้อมคำสั่ง IF พิเศษ

คำตอบบางอย่างที่แนะนำโดยผู้เขียนอื่นประกอบด้วยพิเศษร่วมกันถ้างบเช่นนี้หรือif ($form->count() > 0)if ($form->hasChildren())

เท่าที่ฉันเห็นทุกรูปแบบสามารถมีข้อผิดพลาดเช่นเดียวกับเด็ก ๆ ฉันไม่เชี่ยวชาญกับส่วนประกอบSymfony Formsแต่ในทางปฏิบัติคุณจะไม่ได้รับข้อผิดพลาดบางอย่างของฟอร์มเช่นข้อผิดพลาดในการป้องกัน CSRFหรือข้อผิดพลาดในช่องเพิ่มเติม ฉันขอแนะนำให้ลบการแยกนี้ออก

ใช้โครงสร้างผลลัพธ์ที่ผิดปกติ

ผู้เขียนบางคนแนะนำให้ใส่ข้อผิดพลาดทั้งหมดไว้ในอาร์เรย์ธรรมดา ดังนั้นข้อความแสดงข้อผิดพลาดทั้งหมดของแบบฟอร์มเองและลูกของมันจะถูกเพิ่มลงในอาร์เรย์เดียวกันด้วยกลยุทธ์การจัดทำดัชนีที่แตกต่างกัน: ตามตัวเลขสำหรับข้อผิดพลาดของประเภทเองและตามชื่อสำหรับข้อผิดพลาดลูก ฉันขอแนะนำให้ใช้โครงสร้างข้อมูลที่เป็นมาตรฐานของแบบฟอร์ม:

errors:
    - "Self error"
    - "Another self error"

children
    - "some_child":
        errors:
            - "Children error"
            - "Another children error"

        children
            - "deeper_child":
                errors:
                    - "Children error"
                    - "Another children error"

    - "another_child":
        errors:
            - "Children error"
            - "Another children error"

ผลลัพธ์แบบนั้นสามารถทำซ้ำได้อย่างง่ายดายในภายหลัง

ทางออกของฉัน

นี่คือวิธีแก้ปัญหาของฉัน:

use Symfony\Component\Form\Form;

/**
 * @param Form $form
 * @return array
 */
protected function getFormErrors(Form $form)
{
    $result = [];

    // No need for further processing if form is valid.
    if ($form->isValid()) {
        return $result;
    }

    // Looking for own errors.
    $errors = $form->getErrors();
    if (count($errors)) {
        $result['errors'] = [];
        foreach ($errors as $error) {
            $result['errors'][] = $error->getMessage();
        }
    }

    // Looking for invalid children and collecting errors recursively.
    if ($form->count()) {
        $childErrors = [];
        foreach ($form->all() as $child) {
            if (!$child->isValid()) {
                $childErrors[$child->getName()] = $this->getFormErrors($child);
            }
        }
        if (count($childErrors)) {
            $result['children'] = $childErrors;
        }
    }

    return $result;
}

ฉันหวังว่ามันจะช่วยใครสักคนได้


@weaverryan ช่วยดูวิธีแก้ปัญหาของฉันหน่อยได้ไหม? ถูกต้องหรือมีข้อบกพร่องหรือความเข้าใจผิดหรือไม่? ขอบคุณ!
Slava Fomin II

1

SYMFONY 3.1

ฉันใช้วิธีการคงที่เพื่อจัดการกับการแสดงข้อผิดพลาด

static function serializeFormErrors(Form\Form $form)
{
    $errors = array();
    /**
     * @var  $key
     * @var Form\Form $child
     */
    foreach ($form->all() as $key => $child) {
        if (!$child->isValid()) {
            foreach ($child->getErrors() as $error) {
                $errors[$key] = $error->getMessage();
            }
        }
    }

    return $errors;
}

หวังว่าจะช่วย


1

Symfony 3 และใหม่กว่า

ฉันเพิ่งสร้างฟังก์ชันซึ่งสร้างโครงสร้างของข้อผิดพลาดของฟอร์ม สิ่งนี้จะเป็นประโยชน์ในการส่งคืนรายการข้อผิดพลาดกลับไปที่ส่วนหน้า ขึ้นอยู่กับประเภทฟอร์มที่มี:

'error_bubbling' => false

รหัส:

public static function getFormErrorsTree(FormInterface $form): array
{
    $errors = [];

    if (count($form->getErrors()) > 0) {
        foreach ($form->getErrors() as $error) {
            $errors[] = $error->getMessage();
        }
    } else {
        foreach ($form->all() as $child) {
            $childTree = self::getFormErrorsTree($child);

            if (count($childTree) > 0) {
                $errors[$child->getName()] = $childTree;
            }
        }
    }

    return $errors;
}

เอาท์พุต:

Array
(
    [name] => Array
        (
            [0] => This value is not valid.
        )

    [emails] => Array
        (
            [0] => Array
                (
                    [0] => Given e-mail is not valid.
                    [1] => Given e-mail is not valid #2.
                )
            [1] => Array
                (
                    [0] => Given e-mail is not valid.
                    [1] => Given e-mail is not valid #2.
                )

        )

)

หมายเหตุ : ฉันรู้ว่าข้อผิดพลาดจากฟิลด์ระดับลึกสามารถเขียนทับได้หากระดับที่สูงกว่ามีข้อผิดพลาด แต่นี่เป็นจุดประสงค์สำหรับการใช้งานของฉัน


0

สำหรับ Symfony 2.1:

นี่เป็นทางออกสุดท้ายของฉันที่รวบรวมโซลูชันอื่น ๆ เข้าด้วยกัน:

protected function getAllFormErrorMessages($form)
{
    $retval = array();
    foreach ($form->getErrors() as $key => $error) {
        if($error->getMessagePluralization() !== null) {
            $retval['message'] = $this->get('translator')->transChoice(
                $error->getMessage(), 
                $error->getMessagePluralization(), 
                $error->getMessageParameters(), 
                'validators'
            );
        } else {
            $retval['message'] = $this->get('translator')->trans($error->getMessage(), array(), 'validators');
        }
    }
    foreach ($form->all() as $name => $child) {
        $errors = $this->getAllFormErrorMessages($child);
        if (!empty($errors)) {
           $retval[$name] = $errors; 
        }
    }
    return $retval;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.