program story

Symfony2 : 요청을 양식에 바인딩 한 후 양식 유효성 검증 오류를 얻는 방법

inputbox 2020. 8. 2. 18:34
반응형

Symfony2 : 요청을 양식에 바인딩 한 후 양식 유효성 검증 오류를 얻는 방법


여기 내 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?


가능한 두 가지 방법이 있습니다.

  • 오류 발생시 사용자를 리디렉션하지 않고 {{ form_errors(form) }}템플릿 파일 내에 표시
  • 다음과 같이 액세스 오류 배열 $form->getErrors()

심포니 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);

심포니 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)


아래는 나를 위해 일한 솔루션입니다. 이 함수는 컨트롤러에 있으며 모든 오류 메시지와 그 원인이 된 필드의 구조화 된 배열을 반환합니다.

심포니 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;
}

심포니 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;
}

유효성 검사기를 사용하여 특정 엔터티에 대한 오류를 가져옵니다.

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 참조 :


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

두 번째 인수 ($ flatten)를 true로 전환하지 않으면 Form :: getErrors () 메소드는 이제 FormErrorIterator 인스턴스를 리턴 합니다 . 그런 다음 FormError 인스턴스 를 리턴 하고 current () 메소드없이 getMessage () 메소드를 직접 호출해야합니다.

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

)

가장 중요한 것은 실제로 오류를 얻기 위해 첫 번째 인수를 true로 설정하는 것입니다. 두 번째 인수 ($ flatten)를 기본값 ( true ) 으로두면 FormError 인스턴스가 반환 되고 false로 설정되면 FormErrorIterator 인스턴스 가 반환 됩니다.


더 이상 사용되지 않는 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;
}

플래시 메시지에 만족했습니다 $form->getErrorsAsString()

편집 (Benji_X80에서) : SF3 용 $form->getErrors(true, false);


번역 된 양식 오류 메시지 (Symfony2.1)

이 정보를 찾기 위해 많은 노력을 기울여 왔으므로 양식 오류 번역에 대한 메모를 추가하는 것이 좋습니다.

@Icode4food답은 양식의 모든 오류를 반환합니다. 그러나 반환되는 배열은 메시지 복수화 또는 변환 을 고려하지 않습니다 .

foreach 루프를 수정하여 @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 가지 다른 게시물로 구성되었습니다.


유효성 검사기 서비스를 사용하여 제약 조건 위반을 얻을 수도 있습니다.

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

번역 된 양식 오류 메시지 (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.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."
}

사용자 정의 유효성 검사기를 사용하는 경우 Symfony는의 유효성 검사기에서 생성 된 오류를 반환하지 않습니다 $form->getErrors(). $form->getErrorsAsString()필요한 모든 오류를 반환하지만 결과는 불행히도 배열이 아닌 문자열로 형식화됩니다.

사용 된 Symfony의 버전에 따라 (오류의 출처에 관계없이) 모든 오류를 가져 오는 데 사용하는 방법이 다릅니다.

제안 된 솔루션의 대부분은 모든 하위 양식을 스캔하고 관련 오류를 하나의 배열로 추출하는 재귀 함수 작성과 관련됩니다. Symfony 2.3에는 $form->hasChildren()기능 이 없지만가 있습니다 $form->all().

다음은 Symfony 2.3의 도우미 클래스입니다.이 클래스는 모든 형식에서 모든 오류를 추출하는 데 사용할 수 있습니다. (이것은 Symfony의 github 계정의 관련 버그 티켓에 대한 yapro의 주석 코드를 기반으로합니다.)

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

}

@Jay Seth의 답변을 바탕으로 Ajax Forms를 위해 FormErrors 클래스 버전을 만들었습니다.

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

심포니 버전 : 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 요소의 ID 인 "키"필드가 포함되어 있으므로 오류 메시지를 쉽게 채울 수 있습니다.

부모 내부에 자식 양식이있는 경우 부모 양식 안에 cascade_validation옵션 을 추가하는 것을 잊지 마십시오 setDefaults.


대한 심포니 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;
}

각 오류 설명 텍스트에서 성가신 ' Error : '텍스트를 제거 하려면 str_replace를 사용하십시오 .

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

Twig 오류 표시와 함께 사용하기 위해 Symfony 2.1 이상에서는 단순히 오류를 검색하는 대신 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);
                }
            }
        }
    }

}

$ form-> getErrors ()가 저에게 효과적입니다.


이 솔루션을 생각해 냈습니다. 최신 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;
}

누군가에게 도움이되기를 바랍니다.


심포니 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;
}

도움을 기대


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

참고 : https://stackoverflow.com/questions/6978723/symfony2-how-to-get-form-validation-errors-after-binding-the-request-to-the-fo

반응형