Symfony2: Cách nhận lỗi xác thực biểu mẫu sau khi liên kết yêu cầu với biểu mẫu


110

Đây là saveActionmã của tôi (nơi biểu mẫu chuyển dữ liệu đến)

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();
}

Câu hỏi của tôi là: làm thế nào để tôi nhận được lỗi nếu $form->isValid()trả lại false?

Câu trả lời:


117

Bạn có hai cách khả thi để làm điều đó:

  • không chuyển hướng người dùng khi có lỗi và hiển thị {{ form_errors(form) }}trong tệp mẫu
  • mảng lỗi truy cập là $form->getErrors()

22
Tôi đã làm điều thứ hai mà bạn đề xuất nhưng form-> getErrors () trả về một mảng trống.
putolaruan

2
Tôi cũng đã làm cái đầu tiên (w / php template <? Php echo $ view ['form'] -> lỗi ($ form)?>) Nhưng vẫn trống!
putolaruan

59
@mives Bạn phải đặt error_bubblingthành true trong loại biểu mẫu của mình bằng cách đặt tùy chọn rõ ràng cho từng và mọi trường.
kgilden

5
Nếu bạn đang sử dụng trình xác thực tùy chỉnh, Symfony sẽ không trả lại lỗi do những trình xác thực đó tạo ra trong $ form-> getErrors ().
Jay Sheth

13
Bạn cũng có thể thực hiện $form->getErrors(true)để bao gồm các lỗi của biểu mẫu con
Chris

103

Symfony 2.3 / 2.4:

Hàm này nhận được tất cả các lỗi. Những cái trên biểu mẫu như "Mã thông báo CSRF không hợp lệ. Vui lòng thử gửi lại biểu mẫu." cũng như các lỗi bổ sung trên biểu mẫu con không có lỗi sủi bọt.

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;
}

Để nhận tất cả các lỗi dưới dạng một chuỗi:

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

Symfony 2.5 / 3.0:

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

Tài liệu:
https://github.com/symfony/symfony/blob/master/UPGRADE-2.5.md#form https://github.com/symfony/symfony/blob/master/UPGRADE-3.0.md#form (tại dưới cùng The method Form::getErrorsAsString() was removed:)


1
Đây có vẻ là câu trả lời đúng nhất cho Symfony 2.4 hiện tại.
Slava Fomin II

@Flip hoạt động một cách hoàn hảo trên 2,5
iarroyo

1
Câu trả lời tuyệt vời NHƯNG $errors[$child->getName()] = $this->getErrorMessages($child);đã ném ra ngoại lệ, vì getErrorMessages bị thiếu trong thành phần Symfony \ Bundle \ FrameworkBundle \ Controller \ Controller . Vì vậy, tôi đã thay thế nó bằng$form_errors[$child->getName()] = $child->getErrorsAsString();
Ahad Ali

3
@AhadAli đó là một hàm đệ quy, vì vậy khi bạn đặt đoạn mã vào lớp mà bạn cần chức năng này, nó sẽ có thể gọi chính nó. "Bản sửa lỗi" của bạn sẽ ngăn bạn tiếp cận các biểu mẫu lồng nhau. Nó làm việc cho 37 người khác, nó sẽ làm việc cho bạn quá;)
Lật

@Flip Ah xin lỗi bạn, tôi chỉ mới xem $this->getErrorMessages()và tôi nghĩ nó được gọi trực tiếp bên trong bộ điều khiển và một phần của api Symfony.
Ahad Ali

47

Dưới đây là giải pháp đã làm việc cho tôi. Hàm này nằm trong bộ điều khiển và sẽ trả về một mảng có cấu trúc gồm tất cả các thông báo lỗi và trường gây ra chúng.

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 và mới hơn:

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
Đã cải thiện gist.github.com/2011671 nhưng vẫn không như ý muốn. Tôi muốn các khóa mảng là tên trường, nhưng không phải vậy.
umpirsky

9
@SalmanPK Twig không được tham chiếu ở bất kỳ đâu trong đoạn mã trên. Tôi không tin rằng tôi hiểu bình luận của bạn.
Icode4food

1
Đây là bản sửa lỗi cho ý chính trước đó, điều này hoạt động trong Symfony 2.1.7. gist.github.com/WishCow/5101428
K. Norbert

Dường như có một lỗi đánh máy $this->getFormErrorsnên có $this->getErrorMessagestrong mẫu của bạn trong Symfony2.1
Mick

@umpirsky Để có được tên trường, tôi nhận điều này: $ từ trẻ> getConfig () -> getOptions () [ 'nhãn'] Đã cho tôi mãi mãi để tìm hiểu ...
jsgoupil

35

Sử dụng Trình xác thực để nhận lỗi cho một thực thể cụ thể

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
    }
}

Tham chiếu API:


Cảm ơn, những gì tôi cần 1
Phill Pafford

4
Tôi không chắc rằng đó là một phương pháp tốt để xác thực từng thực thể riêng biệt. Nếu bạn có dạng phân cấp phức tạp thì sao? Vấn đề thứ hai là xác nhận xảy ra hai lần.
Slava Fomin II

3
@SlavaFominII - "Vấn đề thứ hai là xác thực xảy ra hai lần" - Điểm tốt, không có gì được làm mới! Cùng danh sách lỗi sau!
BentCoder

20

Để nhận được thông báo thích hợp (có thể dịch), hiện đang sử dụng SF 2.6.3, đây là chức năng cuối cùng của tôi (vì không có chức năng nào ở trên dường như hoạt động nữa):

 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;
}

như phương thức Form :: getErrors () bây giờ trả về một thể hiện của FormErrorIterator , trừ khi bạn chuyển đối số thứ hai ($ flatten) thành true . (Sau đó, nó sẽ trả về một cá thể FormError và bạn sẽ phải gọi phương thức getMessage () trực tiếp, không có phương thức 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;
}

)

Điều quan trọng nhất thực sự là đặt đối số đầu tiên thành true để nhận lỗi. Để đối số thứ hai ($ flatten) thành giá trị mặc định ( true ) sẽ trả về các thể hiện FormError , trong khi nó sẽ trả về các thể hiện FormErrorIterator khi được đặt thành false.


Đẹp, sử dụng cùng một thứ.
Hư hỏng hữu cơ

phải không :) @KidBinary
Cedo

Tuyệt đối tuyệt đẹp, người bạn đời:)
Hư hữu

Tùy chọn tốt hơn là: $ error = array_map (function ($ item) {return $ item-> current () -> getMessage ();}, $ campaignForm-> getErrors (true, false));
Enrique Quero

Giải pháp tốt cho Symfony 2.7
Yann Chabot

16

Đối với tin nhắn flash của tôi, tôi hài lòng với $form->getErrorsAsString()

Chỉnh sửa (từ Benji_X80): Để sử dụng SF3 $form->getErrors(true, false);


3
Tôi biết đó là một câu trả lời cũ nhưng để tham khảo trong tương lai: This method should only be used to help debug a form.( nguồn )
cheesemacfly

getErrorsAsString () không được dùng nữa trong 3.0, hãy sử dụng: $ form-> getErrors (true, false);
Benji_X80

15

Hàm dành cho symfony 2.1 và mới hơn, không có bất kỳ hàm nào không được chấp nhận:

/**
 * @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;
}

Tôi đã định đăng một câu trả lời mới cho bài đăng này nhưng bạn dường như đã đánh bại tôi. Tôi đã phải xem qua mã nguồn để tìm ra lý do tại sao các lệnh gọi phương thức không được tìm thấy.
Dr.Knowitall

Tôi nhận thấy điều này không kéo theo lỗi từ các mục có lỗi sủi bọt được đặt thành true. SF2.4
kinghfb

@stwe mục đích của IFcâu lệnh đầu tiên là gì? Tại sao nó lại loại trừ lẫn nhau? Theo như tôi thấy: biểu mẫu có thể có lỗi riêng của nó cũng như trẻ em.
Slava Fomin II

4

Thông báo lỗi biểu mẫu đã dịch (Symfony2.1)

Tôi đã đấu tranh rất nhiều để tìm thông tin này vì vậy tôi nghĩ rằng nó chắc chắn đáng để thêm một lưu ý về bản dịch các lỗi biểu mẫu.

@Icode4foodcâu trả lời sẽ trả về tất cả các lỗi của một biểu mẫu. Tuy nhiên, mảng được trả về không tính đến tính đa dạng hóa hoặc dịch của thông báo .

Bạn có thể sửa đổi vòng lặp foreach của @Icode4foodcâu trả lời để có một kết hợp:

  • Nhận tất cả các lỗi của một biểu mẫu cụ thể
  • Trả lại lỗi đã dịch
  • Hãy tính đến đa dạng hóa nếu cần thiết

Nó đây:

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'
            );
    }
}

Câu trả lời này đã được tổng hợp từ 3 bài viết khác nhau:


Chỉ cần thử phiên bản của bạn và nó đã thành công Fatal Error: Call to undefined method Symfony\Component\Form\FormError::getMessagePluralization(). Tôi đang nghi ngờ điều này chỉ dành cho Symfony 2.1?
Czar Pino

4

SYMFONY 3.X

Các phương thức SF 3.X khác được cung cấp ở đây không hoạt động với tôi vì tôi có thể gửi dữ liệu trống vào biểu mẫu (nhưng tôi có các ràng buộc NotNull / NotBlanck). Trong trường hợp này, chuỗi lỗi sẽ giống như sau:

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.
"

Điều đó không hữu ích lắm. Vì vậy, tôi đã làm điều này:

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;
}

Cái nào sẽ trả lại rằng:

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

Bạn cũng có thể sử dụng dịch vụ trình xác thực để nhận các vi phạm ràng buộc:

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

6
Điều này sẽ xác thực đối tượng nhưng không xác thực biểu mẫu. Ví dụ: nếu mã thông báo CRSF là nguyên nhân gây ra lỗi, thông báo sẽ không được đưa vào.
Icode4food

3

Thông báo lỗi biểu mẫu đã dịch (Symfony2.3)

Phiên bản giải quyết vấn đề của tôi:

/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);

Trong Symfony 2.5, bạn có thể gặp lỗi tất cả các trường rất dễ dàng:

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

3

Đối với Symfony 3.2 trở lên sử dụng cái này,

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;
}

Sử dụng str_replace nếu bạn muốn loại bỏ văn bản ' Lỗi: ' khó chịu trong mỗi văn bản mô tả lỗi.

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

2

Nếu bạn đang sử dụng trình xác thực tùy chỉnh, Symfony sẽ không trả lại các lỗi được tạo bởi những trình xác thực đó trong $form->getErrors(). $form->getErrorsAsString()sẽ trả về tất cả các lỗi bạn cần, nhưng không may đầu ra của nó được định dạng là một chuỗi, không phải một mảng.

Phương pháp bạn sử dụng để nhận tất cả các lỗi (bất kể chúng đến từ đâu), phụ thuộc vào phiên bản Symfony bạn đang sử dụng.

Hầu hết các giải pháp được đề xuất liên quan đến việc tạo một hàm đệ quy quét tất cả các biểu mẫu con và trích xuất các lỗi liên quan vào một mảng. Symfony 2.3 không có $form->hasChildren()chức năng này, nhưng nó có $form->all().

Đây là một lớp trợ giúp cho Symfony 2.3, bạn có thể sử dụng lớp này để giải nén tất cả các lỗi từ bất kỳ hình thức nào. (Nó dựa trên mã từ nhận xét của yapro về một phiếu lỗi liên quan trong tài khoản github của 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;
    }
}

Mã gọi:

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

Dựa trên câu trả lời của @Jay Seth, tôi đã tạo một phiên bản của lớp FormErrors đặc biệt dành cho 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;
    }
}

Cách sử dụng (ví dụ: trong hành động của bạn):

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

Phiên bản Symfony: 2.8.4

Phản hồi JSON mẫu:

{
    "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"
    }]
}

Đối tượng lỗi chứa trường "khóa", là id của phần tử DOM đầu vào, vì vậy bạn có thể dễ dàng điền thông báo lỗi.

Nếu bạn có biểu mẫu con bên trong biểu mẫu mẹ, đừng quên thêm cascade_validationtùy chọn bên trong biểu mẫu mẹ setDefaults.


1

Đối với Symfony 2.1 trở đi để sử dụng với hiển thị lỗi Twig, tôi đã thay đổi chức năng để thêm FormError thay vì chỉ truy xuất chúng, bằng cách này bạn có nhiều quyền kiểm soát hơn đối với các lỗi và không phải sử dụng error_bubbling trên từng đầu vào riêng lẻ. Nếu bạn không đặt nó theo cách dưới đây, {{form_errors (form)}} sẽ vẫn trống:

/**
 * @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

Tôi đã đưa ra giải pháp này. Nó hoạt động ổn định với Symfony 2.4 mới nhất .

Tôi sẽ cố gắng đưa ra một số lời giải thích.

Sử dụng trình xác thực riêng

Tôi nghĩ rằng đó là một ý tưởng tồi nếu sử dụng xác thực riêng biệt để xác thực các thực thể và trả về các thông báo vi phạm ràng buộc, như được đề xuất bởi các nhà văn khác.

  1. Bạn sẽ cần phải xác thực thủ công tất cả các thực thể, chỉ định nhóm xác thực, v.v. Với các biểu mẫu phân cấp phức tạp, nó không thực tế chút nào và sẽ nhanh chóng vượt qua khỏi tầm tay.

  2. Bằng cách này, bạn sẽ xác thực biểu mẫu hai lần: một lần với biểu mẫu và một lần với trình xác thực riêng biệt. Đây là một ý tưởng tồi từ quan điểm hiệu suất.

Tôi đề nghị lặp lại đệ quy loại biểu mẫu với nó là con của nó để thu thập thông báo lỗi.

Sử dụng một số phương pháp được đề xuất với câu lệnh IF độc quyền

Một số câu trả lời được đề xuất bởi các tác giả khác chứa các câu lệnh IF loại trừ lẫn nhau như sau: if ($form->count() > 0)hoặc if ($form->hasChildren()).

Theo tôi thấy, hình thức nào cũng có thể có sai sót cả trẻ em. Tôi không phải chuyên gia về thành phần Symfony Forms , nhưng trên thực tế, bạn sẽ không gặp một số lỗi của chính biểu mẫu, chẳng hạn như lỗi bảo vệ CSRF hoặc lỗi trường bổ sung . Tôi đề nghị xóa bỏ sự ngăn cách này.

Sử dụng cấu trúc kết quả không chuẩn hóa

Một số tác giả đề nghị đặt tất cả các lỗi vào bên trong một mảng thuần túy. Vì vậy, tất cả các thông báo lỗi của chính biểu mẫu và các thông báo con của nó sẽ được thêm vào cùng một mảng với các chiến lược lập chỉ mục khác nhau: dựa trên số cho lỗi của chính loại và dựa trên tên cho lỗi con. Tôi đề nghị sử dụng cấu trúc dữ liệu chuẩn hóa của biểu mẫu:

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"

Bằng cách đó, kết quả có thể dễ dàng lặp lại sau này.

Giải pháp của tôi

Vì vậy, đây là giải pháp của tôi cho vấn đề này:

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;
}

Tôi hy vọng nó sẽ giúp một ai đó.


@weaverryan, bạn có thể xem giải pháp của tôi được không? Nó có giá trị không, hay có một nhược điểm hoặc bất kỳ quan niệm sai lầm nào? Cảm ơn bạn!
Slava Fomin II

1

SYMFONY 3.1

Tôi chỉ đơn giản triển khai một phương thức tĩnh để xử lý việc hiển thị lỗi

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;
}

Hy vọng giúp đỡ


1

Symfony 3 và mới hơn

Gần đây tôi đã tạo một hàm tạo một cây lỗi biểu mẫu. Điều này sẽ hữu ích cho việc trả lại danh sách lỗi trở lại giao diện người dùng. Điều này dựa trên các loại biểu mẫu có:

'error_bubbling' => false

Mã:

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;
}

Đầu ra:

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.
                )

        )

)

Lưu ý : Tôi biết rằng lỗi từ các trường cấp sâu hơn có thể bị ghi đè nếu cấp cao hơn có lỗi, nhưng điều này là do tôi sử dụng.


Hoàn hảo cho var_dump, cảm ơn
ReaperSoon

0

Đối với Symfony 2.1:

Đây là giải pháp cuối cùng của tôi kết hợp nhiều giải pháp khác:

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.