@@ -117,35 +117,38 @@ PolyCollection to know which type to use when it encounters an object.
117
117
118
118
namespace Infinite\InvoiceBundle\Form\Type;
119
119
120
- use Symfony\Component\Form\AbstractType as BaseType;
120
+ use Infinite\FormBundle\Form\Type\PolyCollectionType;
121
+ use Infinite\InvoiceBundle\Entity\Invoice;
122
+ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
123
+ use Symfony\Component\Form\AbstractType;
121
124
use Symfony\Component\Form\FormBuilderInterface;
122
- use Symfony\Component\OptionsResolver\OptionsResolverInterface ;
125
+ use Symfony\Component\OptionsResolver\OptionsResolver ;
123
126
124
- class InvoiceType extends BaseType
127
+ class InvoiceType extends AbstractType
125
128
{
126
129
public function buildForm(FormBuilderInterface $builder, array $options)
127
130
{
128
- $builder->add('customer', 'entity' , array( /* ... */ ));
129
- $builder->add('address', 'entity' , array( /* ... */ ));
131
+ $builder->add('customer', EntityType::class , array( /* ... */ ));
132
+ $builder->add('address', EntityType::class , array( /* ... */ ));
130
133
131
- $builder->add('lines', 'infinite_form_polycollection' , array(
134
+ $builder->add('lines', PolycollectionType::class , array(
132
135
'types' => array(
133
- 'invoice_line_type', // The first defined Type becomes the default
134
- 'invoice_product_line_type' ,
136
+ InvoiceLineType::class,
137
+ InvoiceProductLineType::class ,
135
138
),
136
139
'allow_add' => true,
137
140
'allow_delete' => true,
138
141
));
139
142
}
140
143
141
- public function setDefaultOptions(OptionsResolverInterface $resolver)
144
+ public function configureOptions(OptionsResolver $resolver)
142
145
{
143
- $resolver->setDefaults(array('data_class' => 'Infinite\\InvoiceBundle\\Entity\\ Invoice' ));
146
+ $resolver->setDefaults(array('data_class' => Invoice::class ));
144
147
}
145
148
146
- public function getName ()
149
+ public function getBlockPrefix ()
147
150
{
148
- return 'invoice_type ';
151
+ return 'invoice ';
149
152
}
150
153
}
151
154
```
@@ -156,37 +159,40 @@ class InvoiceType extends BaseType
156
159
157
160
namespace Infinite\InvoiceBundle\Form\Type;
158
161
159
- use Symfony\Component\Form\AbstractType as BaseType;
162
+ use Infinite\InvoiceBundle\Entity\InvoiceLine;
163
+ use Symfony\Component\Form\AbstractType;
164
+ use Symfony\Component\Form\Extension\Core\Type\HiddenType;
165
+ use Symfony\Component\Form\Extension\Core\Type\NumberType;
166
+ use Symfony\Component\Form\Extension\Core\Type\TextareaType;
167
+ use Symfony\Component\Form\Extension\Core\Type\TextType;
160
168
use Symfony\Component\Form\FormBuilderInterface;
161
- use Symfony\Component\OptionsResolver\OptionsResolverInterface ;
169
+ use Symfony\Component\OptionsResolver\OptionsResolver ;
162
170
163
- class InvoiceLineType extends BaseType
171
+ class InvoiceLineType extends AbstractType
164
172
{
165
- protected $dataClass = 'Infinite\\InvoiceBundle\\Entity\\InvoiceLine';
166
-
167
173
public function buildForm(FormBuilderInterface $builder, array $options)
168
174
{
169
- $builder->add('quantity', 'number' );
170
- $builder->add('unitAmount', 'text' );
171
- $builder->add('description', 'textarea' );
175
+ $builder->add('quantity', NumberType::class );
176
+ $builder->add('unitAmount', TextType::class );
177
+ $builder->add('description', TextareaType::class );
172
178
173
- $builder->add('_type', 'hidden' , array(
174
- 'data' => $this->getName(),
179
+ $builder->add('_type', HiddenType::class , array(
180
+ 'data' => 'line', // Arbitrary, but must be distinct
175
181
'mapped' => false
176
182
));
177
183
}
178
184
179
- public function setDefaultOptions(OptionsResolverInterface $resolver)
185
+ public function configureOptions(OptionsResolver $resolver)
180
186
{
181
187
$resolver->setDefaults(array(
182
- 'data_class' => $this->dataClass ,
183
- 'model_class' => $this->dataClass ,
188
+ 'data_class' => InvoiceLine::class ,
189
+ 'model_class' => InvoiceLine::class ,
184
190
));
185
191
}
186
192
187
- public function getName ()
193
+ public function getBlockPrefix ()
188
194
{
189
- return 'invoice_line_type ';
195
+ return 'invoice_line ';
190
196
}
191
197
}
192
198
```
@@ -197,29 +203,125 @@ class InvoiceLineType extends BaseType
197
203
198
204
namespace Infinite\InvoiceBundle\Form\Type;
199
205
206
+ use Infinite\InvoiceBundle\Entity\InvoiceProductLine;
207
+ use Symfony\Component\Form\AbstractType;
208
+ use Symfony\Component\Form\Extension\Core\Type\HiddenType;
209
+ use Symfony\Component\Form\Extension\Core\Type\NumberType;
210
+ use Symfony\Component\Form\Extension\Core\Type\TextType;
200
211
use Symfony\Component\Form\FormBuilderInterface;
212
+ use Symfony\Component\OptionsResolver\OptionsResolver;
201
213
202
- class InvoiceProductType extends InvoiceLineType
214
+ class InvoiceProductType extends AbstractType
203
215
{
204
- protected $dataClass = 'Infinite\\InvoiceBundle\\Entity\\InvoiceProductType';
205
-
206
216
public function buildForm(FormBuilderInterface $builder, array $options)
207
217
{
208
- parent::buildForm( $builder, $options );
218
+ $builder->add('quantity', NumberType::class );
209
219
210
- $builder->add('product', 'entity' , array(
220
+ $builder->add('product', EntityType::class , array(
211
221
// entity field definition here
212
222
));
223
+
224
+ $builder->add('_type', HiddenType::class, array(
225
+ 'data' => 'product', // Arbitrary, but must be distinct
226
+ 'mapped' => false
227
+ ));
213
228
}
214
229
215
- public function getName( )
230
+ public function configureOptions(OptionsResolver $resolver )
216
231
{
217
- return 'invoice_product_line_type';
232
+ $resolver->setDefaults(array(
233
+ 'data_class' => InvoiceProductLine::class,
234
+ 'model_class' => InvoiceProductLine::class,
235
+ ));
236
+ }
237
+
238
+ public function getBlockPrefix()
239
+ {
240
+ return 'invoice_product_line';
218
241
}
219
242
}
220
243
```
221
244
222
245
Rendering the form
223
246
------------------
224
247
225
- Coming Soon. Still a work in progress.
248
+ Polycollections require manual work to render. This code can go
249
+ in the same template that renders the rest of the form.
250
+
251
+ You will need to render add buttons from the prototypes array, which is
252
+ keyed on the _ type field in the form definition.
253
+
254
+ It is best illustrated by example.
255
+
256
+ ``` twig
257
+ {# AppBundle:Invoice:add.html.twig #}
258
+
259
+ {% form_theme form.lines _self %}
260
+
261
+ {# ... #}
262
+
263
+ {% block infinite_form_polycollection_row %}
264
+ {% set collectionForm = form %}
265
+ <hr>
266
+ <div class="collection">
267
+ <div class="clearfix">
268
+ <div class="pull-left">
269
+ {{ form_label(collectionForm, 'Invoice lines') }}
270
+ </div>
271
+ <div class="pull-right">
272
+ {% set form = prototypes.line %}
273
+ <a href="#" data-prototype="{{ block('entry_row') | escape }}"
274
+ class="btn btn-success add_item">
275
+ <i class="glyphicon glyphicon-plus"></i> Freight line
276
+ </a>
277
+ {% set form = prototypes.product %}
278
+ <a href="#" data-prototype="{{ block('entry_row') | escape }}"
279
+ class="btn btn-success add_item">
280
+ <i class="glyphicon glyphicon-plus"></i>
281
+ </a>
282
+ </div>
283
+ </div>
284
+ <div class="items">
285
+ {% for form in collectionForm %}
286
+ {{ block('entry_row') }}
287
+ {% endfor %}
288
+ </div>
289
+ </div>
290
+ {% endblock %}
291
+
292
+ {% block entry_row %}
293
+ <div class="item">
294
+ <hr>
295
+ {{ form_widget(form) }}
296
+ </div>
297
+ {% endblock %}
298
+
299
+ {% block invoice_line_widget %}
300
+ <div class="row">
301
+ <div class="col-md-6">{{ form_row(form.description) }}</div>
302
+ <div class="col-md-2">{{ form_row(form.unitAmount) }}</div>
303
+ <div class="col-md-2">{{ form_row(form.quantity) }}</div>
304
+ <div class="col-md-2 text-right">
305
+ <label> </label><br>
306
+ <a href="#" class="btn btn-danger remove_item">
307
+ <i class="glyphicon glyphicon-minus"></i> Remove
308
+ </a>
309
+ </div>
310
+ </div>
311
+ {{ form_rest(form) }}
312
+ {% endblock %}
313
+
314
+ {% block invoice_product_line_widget %}
315
+ <div class="row">
316
+ <div class="col-md-6">{{ form_row(form.product) }}</div>
317
+ <div class="col-md-2 col-md-offset-2">{{ form_row(form.quantity) }}</div>
318
+ <div class="col-md-2 text-right">
319
+ <label> </label><br>
320
+ <a href="#" class="btn btn-danger remove_item">
321
+ <i class="glyphicon glyphicon-minus"></i> Remove
322
+ </a>
323
+ </div>
324
+ </div>
325
+ {{ form_rest(form) }}
326
+ {% endblock %}
327
+ ```
0 commit comments