22

Symfony2でフォームを作成しています。フォームbookには、ユーザーがBooksエンティティのリストから選択できるフィールドが1つだけ含まれています。選択したものがコントローラーにBookあるものに属しているかどうかを確認する必要があります。Author

public class MyFormType extends AbstractType
{
    protected $author;

    public function __construct(Author $author) {
        $this->author = $author;
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add('book', 'entity', array('class' => 'AcmeDemoBundle:Book', 'field' => 'title');
    }

    // ...
}

フォームを送信した後、選択したものがコントローラーにBook書き込まれていることを確認したいと思います。$author

public class MyController
{
    public function doStuffAction() {
        $author = ...;
        $form = $this->createForm(new MyFormType($author));
        $form->bind($this->getRequest());

        // ...
    }
}

残念ながら、私はそれを行う方法を見つけることができません。The Cookbookで説明されているように、カスタムバリデーター制約を作成しようとしましたがEntityManager、バリデーターをサービスとして定義することでasパラメーターを渡すことはできます$authorが、コントローラーからバリデーター制約に渡すことはできません。

class HasValidAuthorConstraintValidator extends ConstraintValidator
{
    private $entityManager;

    public function __construct(EntityManager $entityManager) {
        $this->entityManager = $entityManager;
    }

    public function validate($value, Constraint $constraint) {
        $book = $this->entityManager->getRepository('book')->findOneById($value);
        $author = ...; // That's the data I'm missing

        if(!$book->belongsTo($author))
        {
            $this->context->addViolation(...);
        }
    }
}

このソリューションは、まさに私が探していたものである可能性がありますが、私のフォームはエンティティにバインドされておらず、意図されていません(getData()メソッドからデータを取得しています)。

私の問題の解決策はありますか?これはよくあることですが、どうすれば解決できるのか本当にわかりません。

4

4 に答える 4

32

Ceradの助けを借りて、私はついにそれを理解しました。メソッドからアクセスする必要のあるカスタムパラメータを挿入するには、それらをオプションConstraintValidator::validate()としてに渡す必要があります。Constraint

public class HasValidAuthorConstraint extends Constraint
{
    protected $author;

    public function __construct($options)
    {
        if($options['author'] and $options['author'] instanceof Author)
        {
            $this->author = $options['author'];
        }
        else
        {
            throw new MissingOptionException("...");
        }
    }

    public function getAuthor()
    {
        return $this->author;
    }
}

そして、ConstraintValidatorで:

class HasValidAuthorConstraintValidator extends ConstraintValidator
{
    private $entityManager;

    public function __construct(EntityManager $entityManager) {
        $this->entityManager = $entityManager;
    }

    public function validate($value, Constraint $constraint) {
        $book = $this->entityManager->getRepository('book')->findOneById($value);
        $author = $this->constraint->getAuthor();

        if(!$book->isAuthor($author))
        {
            $this->context->addViolation(...);
        }
    }
}

最後になりましたが、パラメータをバリデーターに渡す必要があります。

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add('book', 'entity', array(
        'class' => 'AcmeDemoBundle:Book',
        'field' => 'title',
        'constraints' => array(
            new HasValidAuthorConstraint(array(
                'author' => $this->author
            ))
        )
    ));
}
于 2013-03-26T16:12:00.027 に答える
3

まず、setAuthorメソッドを制約に追加してから、validateメソッドを微調整します。その場合の秘訣は、それを呼び出すのに最適な場所を決定することです。

バリデーターを本にどのようにバインドしているかは明確ではありません。検証.ymlを使用していますか、それともフォーム内で何かをしていますか?

于 2013-03-26T14:56:13.510 に答える
1

ええと、私はフォーム/検証コンポーネントにそれほど精通していませんが、作成者の名前/ IDで非表示フィールドを使用して、それが同じかどうかを確認できます。

class MyFormType extends AbstractType
{
    protected $author;

    public function __construct(Author $author) {
        $this->author = $author;
    }

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
            ->add('book', 'entity', array('class' => 'AcmeDemoBundle:Book', 'field' => 'title');
            ->add('author_name', 'hidden', array(
                'data' => $this->author->getId(),
            ))
        ;
    }

    // ...
}
于 2013-03-25T19:05:00.357 に答える
-2

Symfony Frameworkバージョン2.1を使用していると、受け入れられた回答が機能しませんでした。これが私がそれを解決した方法です。

class CustomConstraint extends Constraint
{
    public $dependency;
    public $message = 'The error message.';
}

class CustomConstraintValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
        if (!$constraint->dependency->allows($value)) {
            $this->context->addViolation($constraint->message);
        }
    }
}

class CustomFormType extends AbstractType
{
    private $dependency;

    public function __construct(Dependency $dependency)
    {
        $this->dependency = $dependency;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('field', 'type', array(
                'constraints' => array(
                    new CustomConstraint(array('dependency' => $this->dependency))
                )
        ));
    }
} 
于 2016-04-11T17:53:15.090 に答える