2

symfony 2 のエンティティ フィールドで動作するように dataTransformer を取得しようとしています。

環境:

  • ユーザーが選択できる帆を表示するフォーム (チェックボックス)

  • これは、複数ステップのセイル注文プロセスの最初のステップです (後のステップでは、各セイル、色などで利用可能なオプションが表示されます)。

これは私のフォームタイプクラスです:

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Co\QuoteBundle\Form\DataTransformer\SailCollectionToStringsTransformer;

class PartsTypeStep1 extends AbstractType {

public function setDefaultOptions(OptionsResolverInterface $resolver)
{   
    $resolver->setDefaults(array(
        'data_class' => 'Co\QuoteBundle\Entity\Parts',));

    $resolver->setRequired(array('sailsAvailable', 'em'));
}

public function buildForm(FormBuilderInterface $formBuilder, array $options)
{        
    $transformer = new SailCollectionToStringsTransformer($options['em']);

    $formBuilder->add(
        $formBuilder->create('mainsailparts', 'entity', array(
            'class' => 'CoQuoteBundle:Mainsail',
            'choices' => $options['sailsAvailable']['mains'],
            'multiple' => true,
            'expanded' => true,
            'label' => 'Mainsails',))
       ->addModelTransformer($transformer)); //line 58
}

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

上記はエラーなしで機能しますが、変換されたデータは表示されません。ビューは次のとおりです。

__ Race main
__ Cruising main

__チェックボックスの略)

ただし、私が望むビューは次のとおりです。

__ Race main ($1400)
__ Cruising main ($800)

私が持っている変圧器は次のとおりです。

use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Doctrine\Common\Persistence\ObjectManager;
use Co\QuoteBundle\Entity\Sail;
use Doctrine\Common\Collections\ArrayCollection;

class SailCollectionToStringsTransformer implements DataTransformerInterface
{
/**
 * @var ObjectManager
 */
private $om;

/**
 * @param ObjectManager $om
 */
public function __construct(ObjectManager $om)
{
    $this->om = $om;
}

/**
 * Transforms a collection of sails to a collection of strings.
 * @param  ISail|null $sail
 * @return string
 */
public function transform($sailCollection)
{
    if (null === $sailCollection) {
        return null;
    }

    $labels = new ArrayCollection();

    foreach($sailCollection as $sail){
        $labels[] = $sail->getName().' ($'.$sail->getBuildPrice().')';
    }

    return $labels;
}

//reverse transformer... not the issue (yet) because the forward transformer doesn't work

}

これを netbeans デバッガーで実行すると、空の配列がトランスフォーマーに渡されます。ただし、行 58 を に変更し->addViewTransformer($transformer));てデバッグすると、セイル ID を持つ 2 つのブール値が配列キーとしてトランスフォーマーに正しく渡されます。残念ながら、ViewTransformer変更する元の文字列が含まれていないため、使用できません。

主帆を含むべき ArrayCollection が空の ArrayCollection としてトランスフォーマーに渡されるのはなぜですか? この関数は空の$labelsコレクションを返します。

何が間違っているのかわかりません...助けていただければ幸いです!!!! ありがとう。

4

1 に答える 1

1

自分がやろうとしていたことを実装する方法を見つけられませんでした。ただし、私が使用した回避策を以下に説明します。

フォーム タイプ クラスには、フォーム イベント(symfony2 book)を使用し、次のように、コントローラーのパーツ オブジェクトに boatId (帆が対応する) を保存しました。

$partsObject = new Parts($boat->getId());
$form = $this->createForm(new PartsTypeStep1(), $partsObject, array(
                'em' => $this->getDoctrine()->getManager()));

フォーム タイプ クラスは次のようになります。

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Doctrine\ORM\EntityRepository;

class PartsTypeStep1 extends AbstractType {

public function setDefaultOptions(OptionsResolverInterface $resolver)
{   
    $resolver->setDefaults(array(
        'data_class' => 'Co\QuoteBundle\Entity\Parts',));

    $resolver->setRequired(array('em'));
}

public function buildForm(FormBuilderInterface $formBuilder, array $options)
{            
    $factory = $formBuilder->getFormFactory();
    $em = $options['em'];

    $formBuilder->addEventListener(
        FormEvents::PRE_SET_DATA,
        function(FormEvent $event) use($factory, $em){
            $form = $event->getForm();
            $data = $event->getData();

            if (!$data || !$data->getDateTime()) {
                return;
            }
            else {
                $boatClass = $data->getBoatId();

                $formOptions = array(
                            'class' => 'CoQuoteBundle:Mainsail',
                            'multiple' => true,
                            'expanded' => true,
                            'property' => 'displayString',
                            'label' => 'Mainsails',
                            'query_builder' => function(EntityRepository $er) use ($boatClass) {
                                return $er->createQueryBuilder('m')
                                        ->where('m.boatType = :boatClass')
                                        ->setParameter('boatClass', $boatClass);
                            },
                        );
                $form->add($factory->createNamed('mainsailparts', 'entity', null, $formOptions));

                }
        }
    );

}

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

displayStringまた、クラスにプロパティを追加する必要がありMainsailました (文字列の実際の変数ではなく、getter のみを追加しました)。したがって、Mainsailクラスは次のようになります。

public function getDisplayString(){
    return $this->name . ' - ' . $this->descr . ' ($' . $this->buildPrice . ')';
}

この回避策で遭遇した唯一の問題は、クエリが空の結果を返した場合にどうなるかということです。これは、表示するチェックボックスがあるかどうかに関係なく、twig がフォーム ラベル ('Mainsails') を自動的に表示するためです。私はこの問題を次のように回避しました:

            {% if form.mainsailparts|length > 0 %}
                <div class="groupHeading">{{ form_label(form.mainsailparts) }}</div>
                {% for child in form.mainsailparts %}
                    {# render each checkbox .... #}

                {% endfor %}
            {% else %}
                {% do form.mainsailparts.setRendered %}
            {% endif %}

この場合、これが推奨される解決策かどうかはわかりませんが、フォームの検証で機能します (少なくとも帆が選択されていない場合は進行を禁止します。これ以上厳密なものは必要ありません)。

質問(エンティティフィールドにトランスフォーマーを適用する方法)には答えないので、これを答えとしてマークするつもりはありませんが、同じ問題に対処する人にとっては回避策です。

于 2013-07-19T18:26:15.863 に答える