Symfony2 customize form choice labels - symfony

I want my choice labels rendered unescaped
here my FormType code:
$builder
->add('banner', new BannerType())
->add('runtime', 'entity', array(
'class' => 'AdvertisingBundle:Runtime',
'expanded' => true,
'property' => 'label'
))
here the label property:
public function getLabel()
{
return "<div class labelLeft>".$this->description.
"</div><div class labelLeft>".$this->hint."</div>";
}
I want the label rendered raw, which form_theme fragment I need to override?

here my solution:
<table>
{% for option in form.runtime %}
<tr>
<td class="choiceColumn">
{{ form_widget(option) }}
</td>
{{ option.vars.label |raw}}
</tr>
{% endfor %}
</table>

Related

Symfony - Form with multiple entity objects

I'm running Symfony 3.4 LTS and I have an entity Attribute:
<?php
class Attribute
{
private $id;
private $code;
private $value;
private $active;
// My getters and setters
Below the database table:
I would like to get, in a form, all the rows with code == 'productstatus'. I tried:
<?php
$attributes = $this->getDoctrine()->getRepository(Attribute::class)->findBy(['code' => 'productstatus']);
// $attributes contains array with 3 objects 'Attribute'
$form = $this->createFormBuilder($attributes);
$form->add('value', TextType::class);
$output = $form->getForm()->createView();
If I dump() the $output var in Twig:
... I'm unable to make a loop to display the 3 fields with values.
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
Result :
My goal is to allow the user to edit all the values of a specific attributes in the same form (or multiple forms, but in the same page). I already tried with CollectionType without success.
I found a solution: create 2 nested forms and use CollectionType. Hope it helps.
<?php
// Controller
$attributes = $this->getDoctrine()->getRepository(Attribute::class)->findBy(['code' => 'productstatus']);
$form = $this->createForm(AttributeForm::class, ['attributes' => $attributes]);
// AttributeForm
$builder
->add('attributes', CollectionType::class, [
'entry_type' => AttributeValueForm::class,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
]);
// AttributeValueForm
$builder
->add('value', TextType::class, ['label' => false, 'required' => false])
->add('active', CheckboxType::class, ['label' => false, 'required' => false])
// Twig view
{{ form_start(form) }}
{% for attribute in form.attributes.children %}
<tr>
<td>{{ form_widget(attribute.value) }}</td>
<td>{{ form_widget(attribute.active) }}</td>
</tr>
{% endfor %}
{{ form_end(form) }}
You an use an if statement in the your AttributeType like in the example below:
$builder
->add('entree', EntityType::class, array('class'=>'cantineBundle:plat',
'choice_label'=>function($plat){
if($plat->getType()=='Entree'&&$plat->getStatus()=="non reserve"){
return $plat->getNomPlat();
}
},
'multiple'=>false)
);

Symfony2 collection of entities, add new from select

I am starting with Symfony2, excuse me if my question is very easy but:
I have 2 entities:
News (id, title, tags)
Tag (id, news)
I have relations many-to-many
Sample code of News:
/**
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="news", cascade={"persist", "remove"}))
* #ORM\JoinTable(name="news_tags")
*/
private $tags;
Sample code of Tag:
/**
* #ORM\ManyToMany(targetEntity="News", mappedBy="tags")
*/
private $news;
I have a TagType to adding tags to DB, just simple
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('name', 'text');
}
NewsType
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('title', 'text', array(
'attr'=>array(
'maxlength'=>60
)
))
->add('tags', 'collection', array(
'type'=>new TagType(),
'allow_add'=>true,
'allow_delete'=>true,
'by_reference'=>false,
))
;
}
Sample of News form HTML:
<table class="tags table table-hover">
<thead>
<tr>
<th>name</th>
<th>action</th>
</tr>
</thead>
<tbody data-prototype="{% filter escape %}{% include 'XAdminBundle:Form:news_tags_prototype.html.twig' with {'form': form.tags.vars.prototype} %}{% endfilter %}">
{% for tag in form.tags %}
<tr>
<td>
{{ tag.vars.data.name }}
{{ form_widget(tag.name, {'attr': {'class': 'hidden'} }) }}
</td>
<td class="action">
</td>
</tr>
{% endfor %}
</tbody>
</table>
news_tags_prototype.html.twig
<tr>
<td>{{ form_widget(form.name, {'attr': { 'class': 'form-control' } }) }}</td>
<td class="action"></td>
</tr>
In this case when I click Add Tag, I've got a text input and I can add completely new tag, but the only one I want after click Add Tag get a select box with names of Tag entitiess from DB.
How to do this throw js and prototype (suggested by http://symfony.com/doc/current/cookbook/form/form_collections.html).
Thanks for your help!
In TagType, you should go with something like:
$builder->add('name', 'entity', array(
'class' => 'SomeBundle:Tag'));
Which will ensure that the prototype renders as a dropdown instead of a text element. Hope that helps.
Edit: I just realized that you probably need your existing TagType in order to add the tag to the database in the first place. In that case, create a new file called TagDropdownType with my suggested change above and then in your NewsType, change:
->add('tags', 'collection', array(
'type'=>new TagType(),
'allow_add'=>true,
'allow_delete'=>true,
'by_reference'=>false,
))
to:
->add('tags', 'collection', array(
'type'=>new TagDropdownType(),
'allow_add'=>true,
'allow_delete'=>true,
'by_reference'=>false,
))

Field help not showing in Sonata Admin in Parent Admin when embedded

I don't know whether this is a symphony or a sonata admin bundle issue.
I have my main MultimediaAdmin class which has multiple embedded FileAdmin entries.
class MultimediaAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->with('Files')
->add('files','sonata_type_collection',
array('label' => 'Multimedia Files',
'btn_add' => 'Add File',
'by_reference' => 'false',
'type_options' => array('delete' => false)
), array(
'edit' => 'inline',
'template' => 'MyMultimediaBundle:Multimedia:horizontal.fields.html.twig'
)
)
->end()
->with('Tags')
->add('tags')
->end()
;
}
}
I have a custom template styling the appearance of the embedded FileAdmin form which among few fields has one that shows preview of the uploaded media when editing.
/* horizontal.fields.html.twig */
<fieldset>
<div class="sonata-ba-collapsed-fields">
{% for nested_group_field_name, nested_group_field in form.children %}
{% for field_name, nested_field in nested_group_field.children %}
<div class="control-group">
<label class="control-label" for="nested_field.vars['sonata_admin'].admin.trans(nested_field.vars.label" {{ nested_field.vars['required'] ? 'class="required"' : '' }}>{{ nested_field.vars['sonata_admin'].admin.trans(nested_field.vars.label) }}</label>
<div class="controls">
{% if sonata_admin.field_description.associationadmin.formfielddescriptions[field_name] is defined %}
{{ form_widget(nested_field, {
'inline': 'natural',
'edit' : 'inline'
}) }}
{% set dummy = nested_group_field.setrendered %}
{% else %}
{{ form_widget(nested_field) }}
{% endif %}
{% if sonata_admin.field_description.help %}
<span class="help-block sonata-ba-field-help">{{ sonata_admin.admin.trans(sonata_admin.field_description.help, {}, sonata_admin.field_description.translationDomain)|raw }}</span>
{% endif %}
</div>
</div>
{% endfor %}
{% endfor %}
</div>
</fieldset>
Here's FileAdmin which has image preview added to it when editing to show the thumbnail
class FileAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$media = $this->getSubject();
// use $fileFieldOptions so we can add other options to the field
$fileFieldOptions = array('required' => false,'label' => 'Files', 'attr' => array("multiple" => "multiple"), 'by_reference' => false);
if ($media && ($webPath = $media->getWebPath())) {
$fileFieldOptions['help'] = '<img src="'.$webPath.'" class="admin-preview" />';
}
$formMapper
->add('title','text',array('label'=>'Title'))
->add('abstract','textarea',array('label'=>'Abstract'))
->add('language')
->add('format')
->add('file', 'file', $fileFieldOptions)
->add('quality')
;
}
}
The custom form works perfectly in terms of styling but the only problem I have is, it doesn't show the image preview when editing embedded files in the multimedia form. When I go to edit file directly, not under MultimediaAdmin, the image preview works perfectly. Where could I be going wrong?

accessing other properties in twig of an entity field type

I'm trying to display an entity field type expanded and with multiple set to true. However, I want to display the other properties of the entity. This is similar to Symfony2 : accessing entity fields in Twig with an entity field type but that solution hasn't worked for me. I'm getting the error: Item "code" for "" does not exist.
How can I access the other properties of the entity (color in this case)?
Here is what I have so far:
$builder->add('colors', 'entity', array(
'class' => 'PrismPortalCommonBundle:Color',
'property' => 'code',
'expanded' => true,
'multiple' => true,
));
and in the twig template:
{% for color in form.colors %}
<tr>
<td>{{ form_widget(color) }}</td>
<td>{{ color.vars.data.code }}</td>
</tr>
{% endfor %}
In Symfony 2.5 - you can accomplish this by accessing the data from each choice using the child's index value.
In the form builder - as you might expect:
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Generate form
$builder
->add('child', 'entity', array(
'class' => 'MyBundle:Child',
'label' => 'Children',
'property' => 'any_property_for_label',
'expanded' => true,
'multiple' => true
));
}
In the Twig template:
{{ form_start(form) }}
{% for child in form.child %}
{% set index = child.vars.value %}{# get array index #}
{% set entity = form.child.vars.choices[index].data %}{# get entity object #}
<tr>
<td>{{ form_widget(child) }}</td>{# render checkbox #}
<td>{{ entity.name }}</td>
<td>{{ entity.email }}</td>
<td>{{ entity.otherProperty }}</td>
</tr>
{% endfor %}
{{ form_end(form) }}

Creating Repeative Fields inside my Form Symfony2

I am working on a college project where I want to take the attendance of all the students. I have created a model with 3 fields i,e date, present (boolean) and student_id. Now when I try to generate a form out of it, it will display me only these 3 fields. However I want all the students of the class. So I created a loop for students and created an array of attendance objects. Now I am stuck, I don't know how I can pass them to my TWIG file, and I am also confused if it ist the right way to do this. Here is my Model and Controller code
FORM
namespace College\StudentBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class StudentAttendanceType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('date')
->add('present')
;
}
public function getName()
{
return 'college_studentbundle_studentattendancetype';
}
}
CONTROLLER
public function takeAttendanceAction($Department_Id)
{
$students = $this->getDoctrine()
->getRepository('CollegeStudentBundle:Student')
->findAll($Department_Id);
foreach($students as $key => $student){
$attendance[$key] = new StudentAttendance();
$form[$key] = $this->createForm(new StudentAttendanceType(), $attendance[$key]);
}
$request = $this->getRequest();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()
->getEntityManager();
$em->persist($attendance);
$em->flush();
return $this->redirect($this->generateUrl('CollegeStudentBundle_index', array('id' => $Department_Id)));
}
}
return $this->render('CollegeStudentBundle:StudentAttendance:take-attendance.html.twig', array(
'form' => $form->createView(), 'department' => $Department_Id, 'students' => $students,
));
}
How can I render the form in a way that it will display me all the students with a separate checkbox ?
HTML.TWIG
{% block body %}
<form action="{{ path('CollegeStudentBundle_take_attendance',{'id':department} ) }}" method="post" {{ form_enctype(form) }} name="acadimics-form" id="acadimics-form" >
{{ form_errors(form) }}
{{ form_row(forms[0].date) }}
<table id="mytabs" border="1" cellpadding="5" cellspacing="2" width="100%" >
<tr>
<th> Enrolment No. </th>
<th> Student's Name </th>
<th> Present </th>
</tr>
{% for student in students %}
<tr>
<td> {{ student.enrolmentNo }} </td>
<td> {{ student.firstname }} {{ student.lastname }} </td>
<td> {{ form_row(form.present) }} </td>
</tr>
{% endfor %}
{{ form_rest(form) }}
</table>
<input type="submit" value="Take Attendance" />
</form>
</div>
{% endblock %}
Not tested. But there should be a little modification.
The loop in the controller:
foreach($students as $key => $student){
$attendance[$key] = new StudentAttendance();
$form[$key] = $this->createForm(new StudentAttendanceType(), $attendance[$key])->createView();
}
return the array:
return $this->render('CollegeStudentBundle:StudentAttendance:take-attendance.html.twig', array(
'form' => $form, 'department' => $Department_Id, 'students' => $students,
));
In the template:
{% for sform in form %}
{{ form_widget(sform) }}
{% endfor %}
I think you may be on the wrong track. S2 already deals with arrays out of the box.
Read through:
http://symfony.com/doc/current/cookbook/form/form_collections.html
http://symfony.com/doc/current/reference/forms/types/collection.html
You basically want to create a master ListofStudents form and then imbed a StudentAttendence form. You can then pass your array of students to the master form and all the array processing will happen magically.
In your ListOfStudents form you will have something like:
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('students', 'collection', array('type' => new StudentAttendenceType()));
You return the variable students to the template and you're calling student.firstname in twig, it should be students.firstname and you should keep your 'form' => $form->createView() in the return of your controller.
I think it should work better, hope this help!

Resources