web-dev-qa-db-ja.com

Symfony 2フォームでdata-prototype属性をカスタマイズする方法

何十年も前から、Symfony 2とフォームの問題をブロックしています。

Webサイトエンティティのフォームを取得しました。 「Websites」はWebサイトのエンティティのコレクションであり、各Webサイトには「type」と「url」の2つの属性が含まれています。

データベースに複数のWebサイトを追加する場合は、「別のWebサイトを追加」リンクをクリックして、別のWebサイト行をフォームに追加します。したがって、送信ボタンをクリックすると、1つまたはX個のWebサイトを同時に追加できます。

行を追加するこのプロセスでは、Webサイトのサブフォームを生成できるdata-prototype属性を使用します。

問題は、フォームをカスタマイズして優れたグラフィックレンダリングを実現することです...

<div class="informations_widget">{{ form_widget(website.type.code) }}</div>
<div class="informations_error">{{ form_errors(website.type) }}</div>
<div class="informations_widget">{{ form_widget(website.url) }}</div>
<div class="informations_error">{{ form_errors(website.url) }}</div>

ただし、データプロトタイプは、HTMLおよびCSSタグとプロパティを使用して、このカスタマイズを考慮しません。 Symfonyのレンダリングを維持します。

<div>
<label class=" required">$$name$$</label>
<div id="jobcast_profilebundle_websitestype_websites_$$name$$">
<div>
<label class=" required">Type</label>
<div id="jobcast_profilebundle_websitestype_websites_$$name$$_type">
<div>
<label for="jobcast_profilebundle_websitestype_websites_$$name$$_type_code" class=" required">label</label>
<select id="jobcast_profilebundle_websitestype_websites_$$name$$_type_code" name="jobcast_profilebundle_websitestype[websites][$$name$$][type][code]" required="required">
<option value="WEB-OTHER">Autre</option>
<option value="WEB-RSS">Flux RSS</option>
...
</select>
</div>
</div>
</div>
<div>
<label for="jobcast_profilebundle_websitestype_websites_$$name$$_url" class=" required">Adresse</label>
<input  type="url" id="jobcast_profilebundle_websitestype_websites_$$name$$_url" name="jobcast_profilebundle_websitestype[websites][$$name$$][url]" required="required" value="" />
</div>
</div>
</div>

誰もがそのハックをする考えを持っていますか?

53
j.2bb

少し古いですが、ここに致命的な単純な解決策があります。

アイデアは、Twigテンプレートを使用してコレクションアイテムをレンダリングすることです。したがって、data-prototype="..."タグ。まるで普通の普通の形のように。

MainForm.html.twigで:

<div id="collectionContainer"
     data-prototype="
         {% filter escape %}
             {{ include('MyBundle:MyViewsDirectory:prototype.html.twig', { 'form': form.myForm.vars.prototype }) }}
         {% endfilter %}">
</div>

そしてMyBundle:MyViewsDirectory:prototype.html.twig:

<div>
    <!-- customize as you wish -->
    {{ form_label(form.field1) }}
    {{ form_widget(form.field1) }}
    {{ form_label(form.field2) }}
    {{ form_widget(form.field2) }}
</div>

クレジット: https://Gist.github.com/tobalgists/403221

73
Jivan

私はこの質問がかなり古いことを知っていますが、私は同じ問題を抱えていました。これを達成するためにtwig macroを使用しています。マクロは関数のようなものであり、異なる引数でレンダリングできます。

_{% macro information_prototype(website) %}
    <div class="informations_widget">{{ form_widget(website.type.code) }}</div>
    <div class="informations_error">{{ form_errors(website.type) }}</div>
    <div class="informations_widget">{{ form_widget(website.url) }}</div>
    <div class="informations_error">{{ form_errors(website.url) }}</div>
{% endmacro %}
_

これで、必要な場所にこのマクロをレンダリングできます。 information_prototype()はマクロの名前であり、任意の名前を付けることができます。マクロを使用して特定のアイテムとプロトタイプを同じ方法でレンダリングする場合は、次のようにします。

_<div class="collection" data-prototype="{{ _self.information_prototype(form.websites.vars.prototype)|e }}">
    {% for website in form.websites %}
        {{ _self.information_prototype(website) }}
    {% endfor %}
    <button class="add-collection">Add Information</button>
</div>
_

_form.websites.vars.prototype_は、指定した_prototype_name_を持つフォームのプロトタイプデータを保持します。同じテンプレートでマクロを使用する場合は、__self.+macroname_を使用します。

Twigドキュメント でマクロの詳細を確認できます。

47
Akkumulator

おそらくあなたはそれ以来知っているでしょうが、ここに他の人のための解決策があります。

新しいテンプレートを作成し、このコードをコピーして貼り付けます: https://Gist.github.com/1294186

次に、カスタマイズするフォームを含むテンプレートで、これを実行してフォームに適用します。

{% form_theme form 'YourBundle:Deal:Theme/_field-prototype.html.twig' %}
25

回答が非常に遅いことは知っていますが、訪問者にとっては役に立つかもしれません。

テーマファイルでは、1つのブロックを使用して、次のようにWebサイトウィジェットのすべてのコレクションエントリをレンダリングできます。

{% block _jobcast_profilebundle_websitestype_websites_entry_widget %}
     <div class="informations_widget">{{ form_widget(form.type.code) }}</div>
     <div class="informations_error">{{ form_errors(form.type) }}</div>
     <div class="informations_widget">{{ form_widget(form.url) }}</div>
     <div class="informations_error">{{ form_errors(form.url) }}</div>
{% endblock %}

また、次のようにコレクションウィジェット行のテーマブロックを作成します。

{% block _quiz_question_answers_row %}
     {% if prototype is defined %}
        {%- set attr = attr | merge({'data-prototype': form_row(prototype) }) -%}
    {% endif %}

     {{ form_errors(form) }}

     {% for child in form %}
         {{ form_row(child) }}
     {% endfor %}
{% endblock %}

これで、プロトタイプとレンダリングされたコレクションのエントリは同じになります。

5
Karim

最近、同様の問題に遭遇しました。 htmlで明示的に設定せずにコレクションプロトタイプをオーバーライドする方法は次のとおりです。

{% set customPrototype %}
    {% filter escape %}
        {% include 'AcmeBundle:Controller:customCollectionPrototype.html.twig' with { 'form': form.collection.vars.prototype } %}
    {% endfilter %}
{% endset %}
{{ form_label(form.collection) }}
{{ form_widget(form.collection, { 'attr': { 'data-prototype': customPrototype } }) }}

カスタムの小枝で何でもできます。例えば:

<div data-form-collection="item" data-form-collection-index="__name__" class="collection-item">
<div class="collection-box col-sm-10 col-sm-offset-2 padding-top-20">
    <div class="row form-horizontal form-group">
        <div class="col-sm-4">
            {{ form_label(form.field0) }}
            {{ form_widget(form.field0) }}
        </div>
        <div class="col-sm-3">
            {{ form_label(form.field1) }}
            {{ form_widget(form.field1) }}
        </div>
        <label class="col-sm-3 control-label text-right">
            <button data-form-collection="delete" class="btn btn-danger">
                <i class="fa fa-times collection-button-remove"></i>{{ 'form.collection.delete'|trans }}
            </button>
        </label>
    </div>
</div>

特定の場所でのみ行う必要があり、すべてのコレクションに適用可能なグローバルオーバーライドが必要ない場合に役立ちます。

5

似たような問題がありました。あなたのケースのためにこれを微調整する必要があるかもしれませんが、誰かがそれを役に立つと思うかもしれません。

カスタムテンプレート「テーマ」を保持する新しいテンプレートファイルを作成します

./src/Company/TestBundle/Resources/views/Forms/fields.html.twig

通常、使用できます form_row フィールドのラベル、エラー、ウィジェットを表示する関数。しかし、私の場合は、ウィジェットを表示したかっただけです。あなたが言うように、データプロトタイプ機能を使用するとラベルも表示されるので、新しいfields.html.twigで、フィールドの外観に合わせてカスタムコードを入力します。

{% block form_row %}
{% spaceless %}
        {{ form_widget(form) }}
{% endspaceless %}
{% endblock form_row %}

コンテナdivとラベルとエラーを削除し、ウィジェットを残しました。

次に、フォームを表示するtwigファイルで、{%extends ...%}の後にこれを追加します

{% form_theme form 'CompanyTestBundle:Form:fields.html.twig' %}

そして今、form_widget(form.yourVariable.var.prototype)はフィールドのみをレンダリングし、それ以外は何もレンダリングしません。

2
targnation

アプリケーション全体のフォームテーマがプロトタイプに適用されます。 アプリケーション全体のカスタマイズの作成 を参照してください

1

こちら カスタムデータプロトタイプのサンプルコード:

{{ form_widget(form.emails.get('prototype')) | e }}

ここで、emails —コレクション。

1
Evgeny Smirnov

システム全体でテンプレートを定義する必要がない場合は、twigテンプレートにテンプレートを設定し、twigを使用してください。

{# using the profiler, you can find the block widget tested by twig #}
{% block my_block_widget %}
    <div >
      <p>My template for collection</p>
        <div >
          {{ form_row(form.field1)}}
        </div>
        <div>
          {{ form_row(form.field2)}}
        </div>
    </div>
{% endblock %}

{% form_theme form.my_collection _self %}

<button data-form-prototype="{{ form_widget(form.my_collection.vars.prototype) )|e }}" >Add a new entry</button>
0
Julien Fastré

異なる既存のコレクションアイテムVSプロトタイプをカスタマイズするには、次のようにcollection_widgetをオーバーライドできます。

{%- block collection_widget -%}
    {% if prototype is defined %}
        {%- set attr = attr|merge({'data-prototype': form_row(prototype, {'inPrototype': true} ) }) -%}
    {% endif %}
    {{- block('form_widget') -}}
{%- endblock collection_widget -%}

そして、カスタムエントリで:

{% block _myCollection_entry_row %}

  {% if(inPrototype is defined) %}
      {# Something special only for prototype here #}
  {% endif %}
{% endblock %}
0
Leto