1

私はSymfony-2.1とPropelで基本的なCRUDアプリケーションに取り組んでいます。理想的には、私のモデルは推進XMLスキーマで定義され、GUIは変更を反映するように自動的に更新されます。与えられた時間制限の範囲内でそれが可能になるとは思いませんが、できるだけ近づこうとしています。

私の最初の妥協点は、フォームタイプを手動で作成することでした。これは、推進フォームタイプジェネレーターがかなり初歩的なものだからです。しかし、手動での採用のレベルを維持するために(たとえば、新しいモデルタイプを追加する場合)、カスタムフォームタイプの定義によって次の問題を完全に解決したいと思います。

私は適度に複雑なタイトルモデルを持っています。これは、TitleFragmentモデル(歴史的な出版物のメイン、サブ、およびショートタイトルを表す)と1対多の関係にあります。タイトルを編集するためのHTMLフォームで、標準の「1つ追加」動作を実装して、別のTitleFragmentを追加できるようにしました(つまり、symfonyクックブックで説明されています)。

クックブックソリューションはフォーム要素のリスト構造を提案し、そのフォーム要素でjQueryコントロール要素生成コードをトリガーするために2つのJavaScriptインジケータークラスを追加しました。

<form [...]>
 <ol class="collection-editor collection-sortable" 
      data-prototype="{{ form_widget(form.titleFragments.vars.prototype)|e }}">
    {% for titleFragment in form.titleFragments %}
        <li>
        {{ form_widget(titleFragment) }}
        </li>
    {% endfor %}
  </ol>
  [...]
</form>

カスタムフォームタイプのsymfonyフォームテーマテクニックを使用して、そのマークアップを自動的に生成したいと思います。これを実現するために、symfonyコレクションのフォームタイプを継承し、その名前を変更して、カスタムフォームテーマをそのフォームに適用できるようにしました。

class SortableCollectionType extends \Symfony\Component\Form\Extension\Core\Type\CollectionType {
    public function getName() {
        return 'sortableCollection'; 
    }
}

ここで、デフォルトのsymfonyフォームテーマ(form_div_layout.html.twig)をsortableCollection_widgetブロックで拡張して、コレクションをリストとして強制的にレンダリングし、JavaScriptインジケータークラスをリストに添付する必要があります(コードサンプル#1のように)。

問題は、テンプレートでは、form.titleFragmentsがモデルに依存することです(データはTitleモデルのTitleFragmentsの基になるコレクションにバインドする必要があるため、常にモデルに依存します)。

class TitleType extends BaseAbstractType {

public function buildForm(FormBuilderInterface $builder, array $options) {

    $builder->add('titleFragments', // no choice for a generic name here

      new Form\DerivedType\SortableCollectionType(), array( 
        'type' => new TitlefragmentType(),
        'allow_add' => true,
        'by_reference' => false,
    ));
}
}

バージョン1.2以降、twigはオブジェクトプロパティへの動的アクセス(属性関数を使用)をサポートしているため、プロパティの名前(たとえば、'titleFragments')をテンプレートに渡すことを考えました。

カスタムフォームタイプから小枝テンプレートまでデータを取得する方法を誰かが考えていますか?もちろん冗長で少し不器用ですが、それは問題ありません。

    $builder->add('titleFragments', 
      new Form\DerivedType\SortableCollectionType(), array( 
        'type' => new TitlefragmentType(),
        'options' => array('collectionPropertyName' => 'titleFragments'),

フォームビルダー用のSymfonyAPIが特に役立つとは思いませんでした。

4

1 に答える 1

0

ビューにデータを渡すには、フォームタイプのfinishViewメソッドを使用できます。

public function finishView(FormView $view, FormInterface $form, array $options){
        $view->vars['modelClass'] = $this->modelClass;
}

data_classはフォームタイプで定義されているため、この値を自動的に計算することもできます。コレクションにネストされた型が含まれている場合は、プロトタイプ要素IDプレースホルダー(prototypeName)も自動的にオーバーライドします。

public function buildForm(FormBuilderInterface $builder, array $options)
{
    parent::buildForm($builder, $options);

    // extract unqualified class name and pass it to the view
    // this allows more accurate control elements (instead of "add component",
    // one can use "add modelClass")
    $dataClassStr = $options['type']->getOption('data_class');
    $parts = explode('\\', $dataClassStr);
    $this->modelClass = array_pop($parts);

    $prototypeName = '__' . $this->modelClass . 'ID__';

    if ($options['allow_add'] && $options['prototype']) {
        $prototype = $builder->create($prototypeName, $options['type'], array_replace(array(
            'label' => $options['prototype_name'] . 'label__',
        ), $options['options']));
        $builder->setAttribute('prototype', $prototype->getForm());
    }
}

Twigテンプレートでは、ビューに渡されるデータはform.vars変数を介して利用できます。

{% block sortableCollection_widget %}
{% spaceless %}

    {# [...] code copied from the default collection widget #}

    <a href="#" class="sortableCollectionWidget add-entity">
        {{ form.vars.modelClass|trans }} add one
    </a>

    {# For the javascript to have access to the translated modelClass name.
       The up and down sortable controls need this to be more expressive.   #}

    <input type="hidden" name="modelClassName" value="{{ form.vars.modelClass }}"/>

{% endspaceless %}
{% endblock %}
于 2013-03-04T12:49:59.250 に答える