3

次のシナリオでは、Department を Review にバインドするロジックをどこに配置する必要がありますか。

エンティティ:

  • ディーラー(部門が多い)
  • 部門 (1 つのタイプがあります)
  • 部門タイプ
  • レビュー (1 つの販売店と 1 つの部門があります)

私の ReviewForm では、ユーザーが Dealership と DepartmentType を選択できるようにする必要があります。その後、なんらかの形式のコールバックまたはプレ/ポスト バインドで、どの部門をレビューにバインドするかをユーザーから判断します。

また、Department が Dealership の子であることを検証できるように、検証の前にこれを行う必要があります。

注: レビューは、トラバーサルやその他のロジックを容易にするために Department に関連付けることができる場合でも、Dealership と Department の両方に関連付けられます。


これまでに試した2つのアプローチがありますが、行き止まり/混乱に達しました。

  • フォームの DepartmentType の DataTransformer ですが、これを正しく理解しているかどうかわかりません。変換/逆変換メソッドが、フィールド オブジェクトではなく、レビュー オブジェクトに渡されていました。
  • PRE_BIND、検証前に発生しますが、処理する生データしかなく、オブジェクトはありません
  • POST_BIND、検証後に発生します:(

リレーションシップの検証の最終ステップとして、比較的単純なバリデーターで作業を行う必要がありますが、どの時点でこのようなオブジェクトにデータをバインドするつもりなのかわかりません。ポインタはありますか?

4

2 に答える 2

2

検証も POST_BIND リスナーで行われるため、POST_BIND リスナーを検証リスナーよりも高い優先度 (つまり、0 より大きいもの) で単純に追加できます。

リスナーを書いている場合:

$builder->addEventListener(FormEvents::POST_BIND, $myListener, 10);

サブスクライバーを書いている場合:

public static function getSubscribedEvents()
{
    return array(
        FormEvents::POST_BIND => array('postBind', 10),
    );
}

public function postBind(FormEvent $event)
{
    ...
}
于 2012-07-25T17:36:48.757 に答える
1

各 DepartmentType を表す選択肢を含む標準 (つまり、Doctrine ではない) 選択肢タイプを使用します。

次に、DataTransformer を使用して、選択したオプションを関連する型に変換します。逆も同様です。


カスタム FormType は次のようになります。

class Department extends AbstractType
{
    private $em;

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

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $transformer = new DepartmentToTypeTransformer($this->em);
        $builder->addViewTransformer($transformer, true);

        $builder->getParent()->addEventListener(FormEvents::PRE_BIND, function($event) use ($transformer) {
            $data = (object) $event->getData();
            $transformer->setDealership($data->dealership);
        });
    }

    public function getParent()
    {
        return 'choice';
    }

    public function getName()
    {
        return 'department';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $choices = array();

        foreach ($this->em->getRepository('AcmeDemoBundle:DepartmentType')->findAll() as $type) {
            $choices[$type->getId()] = (string) $type;
        }

        $resolver->setDefaults(array(
            'choices' => $choices,
            'expanded' => true
        ));
    }
}

変換で使用するために、Dealership を DataTransformer に渡すことに注意してください。


そして、DataTransformer は次のようになります。

class DepartmentToTypeTransformer implements DataTransformerInterface
{
    private $em;
    private $dealership;

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

    public function transform($department)
    {
        if (null === $department) {
            return $department;
        }

        return $department->getType()->getId();
    }

    public function reverseTransform($type)
    {
        if (null === $type) {
            return $type;
        }

        return $this->em->getRepository('AcmeDemoBundle:Department')->findOneBy(array(
            'dealership' => $this->getDealership(),
            'type' => $type
        ));
    }

    public function getDealership() {
        return $this->dealership;
    }

    public function setDealership($dealership) {
        $this->dealership = $dealership;
        return $this;
    }
}

トランスフォーマーに渡されるものに関する混乱は、バインドしているトランスフォーマーが既存の動作に追加されていることが原因である可能性が最も高いため、trueaddViewTransformer の 2 番目のパラメーターとして追加してみてください。

    $transformer = new DepartmentToTypeTransformer($this->em);
    $builder->addViewTransformer($transformer, true);

ドキュメントから:

FormBuilder::addViewTransformer(
    DataTransformerInterface $viewTransformer,
    Boolean $forcePrepend = false
)

Appends / prepends a transformer to the view transformer chain.
于 2012-07-26T12:41:36.927 に答える