Closed 3kynox closed 8 years ago
I get out of this error by settings my forms as service
brunobundle_moyencomm:
class: brunoBundle\Form\MoyenCommType
tags:
- { name: form.type }
brunobundle_telephone:
class: brunoBundle\Form\TelephoneType
tags:
- { name: form.type }
brunobundle_email:
class: brunoBundle\Form\EmailType
tags:
- { name: form.type }
brunobundle_adresse:
class: brunoBundle\Form\AdresseType
tags:
- { name: form.type }
But now it returns nothing
Any idea ?
Currently we don't provide a default template for polycollection. For now, add something like this to the twig template that contains your form:
{% form_theme form.moyensComm _self %}
{% block _brunobundle_bruno_moyensComm_widget %}
{# Example polycollection template #}
<div class="collection">
<a class="btn btn-default add_item" href="#" data-prototype="{{ form_row(form.vars.prototypes.brunobundle_email) | escape }}">Add email</a>
<a class="btn btn-default add_item" href="#" data-prototype="{{ form_row(form.vars.prototypes.brunobundle_telephone) | escape }}">Add telephone</a>
<a class="btn btn-default add_item" href="#" data-prototype="{{ form_row(form.vars.prototypes.brunobundle_adresse) | escape }}">Add adresse</a>
<hr />
<div class="items">
{% for subForm in form %}
{{ form_row(subForm) }}
{% endfor %}
</div>
</div>
{% endblock %}
{% block _brunobundle_bruno_moyensComm_entry_row %}
{# Example polycollection row template #}
<div class="item">
<a class="btn btn-danger remove_item pull-right" href="#">Remove</a>
{{ form_widget(form._type) }}
{{ form_widget(form) }} {# Can be overridden - see below #}
{{ form_errors(form) }}
<hr />
</div>
{% endblock %}
{% block brunobundle_adresse_widget %}
{# Example content for row template #}
{{ form_row(form.line1, {label: 'Line 1'}) }}
{{ form_row(form.line2, {label: 'Line 2'}) }}
{{ form_row(form.line3, {label: 'Line 3'}) }}
{% endblock %}
And the appropriate JavaScript to initialise the collection:
$(function() {
$('.collection').each(function() {
var coll = $(this);
new infinite.Collection(
coll.find('.items'),
coll.find('.add_item'),
{
itemSelector: '.item',
removeSelector: '.remove_item'
}
);
});
});
Hello again and thanks for answer.
I almost get it to work, data is just not displayed
If I make a dump of "subForm" inside {% for subForm in form %} here is the results
and if I make a dump of "form._type" inside the entry_row template, no moyensComm data
Thanks for help
Ah! Back in BrunoType.php, change the types
array to say:
'types' => array(
'brunobundle_telephone',
'brunobundle_email',
'brunobundle_adresse'
),
It gets confused if the base form is in there too.
Thanks for answer, BrunoType seems OK
// brunoBundle/Form/BrunoType.php
namespace brunoBundle\Form;
use brunoBundle\Form\Type\GenderType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class BrunoType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('text')
->add('textarea')
->add('email', 'email')
->add('entier')
->add('money', 'money')
->add('date')
->add('choice', new GenderType(), array(
'expanded' => true,
'multiple' => false
))
->add('moyensComm', 'infinite_form_polycollection', array(
'types' => array(
'brunobundle_moyencomm',
'brunobundle_telephone',
'brunobundle_email',
'brunobundle_adresse'
),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => 'Moyens de Communication'
));
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'brunoBundle\Entity\Bruno'
));
}
/**
* @return string
*/
public function getName()
{
return 'brunobundle_bruno';
}
}
Here is MoyenCommType
// brunoBundle/Form/MoyenCommType.php
namespace brunoBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormInterface;
use brunoBundle\Entity\Telephone;
class MoyenCommType extends AbstractType
{
protected $dataClass = 'brunoBundle\Entity\MoyenComm';
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('_type', 'hidden', array(
'data' => $this->getName(),
'mapped' => false
));
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => $this->dataClass,
'model_class' => $this->dataClass,
));
}
/**
* @return string
*/
public function getName()
{
return 'brunobundle_moyencomm';
}
}
And one of the childrens
// brunoBundle/Form/TelephoneType.php
namespace brunoBundle\Form;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TelephoneType extends MoyenCommType
{
protected $dataClass = 'brunoBundle\Entity\TelephoneType';
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('numero')
;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'brunoBundle\Entity\Telephone'
));
}
/**
* @return string
*/
public function getName()
{
return 'brunobundle_telephone';
}
}
The theme looks like this
// brunoBundle/Resources/views/Form/polycollection.html.twig
{% use "bootstrap_3_horizontal_layout.html.twig" %}
{% block _brunobundle_bruno_moyensComm_widget %}
<div class="collection">
<div class="items">
{% for subForm in form %}
{#{{ dump(subForm) }}#}
{{ form_row(subForm) }}
{% endfor %}
</div>
<hr />
<a class="btn btn-default add_item" href="#" data-prototype="{{ form_row(form.vars.prototypes.brunobundle_telephone) | escape }}">Ajouter Téléphone</a>
<a class="btn btn-default add_item" href="#" data-prototype="{{ form_row(form.vars.prototypes.brunobundle_email) | escape }}">Ajouter Email</a>
<a class="btn btn-default add_item" href="#" data-prototype="{{ form_row(form.vars.prototypes.brunobundle_adresse) | escape }}">Ajouter Adresse</a>
</div>
{% endblock %}
{% block _brunobundle_bruno_moyensComm_entry_row %}
<div class="item">
<a class="remove_item pull-right" href="#"><span class="glyphicon glyphicon-remove-circle"></span></a>
{#{{ dump(form._type) }}#}
{{ form_widget(form._type) }}
{{ form_widget(form) }}
{{ form_errors(form) }}
<hr />
</div>
{% endblock %}
{% block brunobundle_telephone_widget %}
<br />
{{ form_row(form.numero, {label: 'Numéro'}) }}
{% endblock %}
{% block brunobundle_email_widget %}
<br />
{{ form_row(form.email, {label: 'Email'}) }}
{% endblock %}
{% block brunobundle_adresse_widget %}
<br />
{{ form_row(form.adresse, {label: 'Adresse'}) }}
{{ form_row(form.codePostal, {label: 'Code Postal'}) }}
{{ form_row(form.ville, {label: 'Ville'}) }}
{% endblock %}
and is called in form edit page
// brunoBundle/Resources/views/Bruno/edit.html.twig
{% extends '::base.html.twig' %}
{% block pageTitle %}formType : Édition{% endblock %}
{% block body -%}
{% form_theme form 'brunoBundle:Form:polycollection.html.twig' %}
{{ form(form) }}
<ul class="record_actions">
<li>
<a href="{{ path('bruno') }}">
Back to the list
</a>
</li>
<li>{{ form(delete_form) }}</li>
</ul>
{% endblock %}
JS code resides on base layout
// app/Resources/views/base.html.twig
// ...
{% block javascripts %}
{% javascripts '@jquery' '@bootstrap_js' %}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% javascripts '@infinite_js' %}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
<script>
jQuery(document).ready(function() {
$('.collection').each(function() {
var coll = $(this);
new infinite.Collection(
coll.find('.items'),
coll.find('.add_item'),
{
itemSelector: '.item',
removeSelector: '.remove_item'
}
);
});
});
</script>
{% endblock %}
// ...
Sorry for all this massive paste and thanks again for lights :)
According to your example, if I remove 'brunobundle_moyencomm', from array, I get error :
The form's view data is expected to be an instance of class brunoBundle\Entity\Telephone, but is an instance of class brunoBundle\Entity\Email. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class brunoBundle\Entity\Email to an instance of brunoBundle\Entity\Telephone.
I hope that helps.
What does EmailType look like?
Oh, just noticed a problem in TelephoneType. Set the $dataClass to 'brunoBundle\Entity\Telephone' and amend setDefaultOptions() to call parent::setDefaultOptions(). Better check the other child forms too.
Works !
EmailType and AdresseType was not having protected $dataClass, only TelephoneType was having, then I corrected and pointed it out to entity instead of formType and finally I removed setDefaultOption method from childs.
class EmailType extends MoyenCommType
{
protected $dataClass = 'brunoBundle\Entity\Email';
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('email')
;
}
/**
* @return string
*/
public function getName()
{
return 'brunobundle_email';
}
}
Thanks for great support, waiting now for future great updates :P
Now managing updateAction from controller.
EDIT:
Controller and DB update works too, here is my editAction code :
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('brunoBundle:Bruno')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Bruno entity.');
}
$moyensComm = new ArrayCollection();
foreach ($entity->getMoyensComm() as $moyenComm) {
$moyensComm->add($moyenComm);
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
foreach($editForm->getViewData()->getMoyensComm() as $data) {
if($data->getBruno() == null){
$data->setBruno($entity);
}
}
foreach ($moyensComm as $moyenComm) {
if (false === $entity->getMoyensComm()->contains($moyenComm)) {
$em->remove($moyenComm);
}
}
$em->flush();
return $this->redirect($this->generateUrl('bruno_edit', array('id' => $id)));
}
return $this->render('brunoBundle:Bruno:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
\o/
Hello,
I got some problems making polycollection to work. InfiniteFormBundle is correctly installed.
I got a base contact entity (named bruno) whith inside a 'moyensComm' attribute set as ArrayCollection
Mapping for that class include a oneToMany relation to MoyenComm abstract entity described as follow
And here is the MoyenComm class
Which have inheritance ORM set to three subclasses (Telephone, Email & Adresse) and inversed map
Now I build my base form
And here is the MoyenCommType
... and subclasses TelephoneType, EmailType, etc... that extends MoyenCommType.
The error I get is
I checked the name exactly and all seem to be correct according to InfiniteFormBundle documentation.
Some help possible please ?