I have following problem:
my Query with joins contains all the nesessary data but symfony / twig creates more queries
each {{ entity.group.name }} produces a new query
controller:
/**
* #Route("/gameplan", name="game_plan")
* #Template()
* //#Secure(roles="ROLE_USER")
*/
public function indexAction()
{
$em = $this->getDoctrine()->getEntityManager();
$entities = $em->getRepository('OnemediaFeedFighterBundle:Game')->createQueryBuilder('q')
->leftJoin('q.group', 'g')
->leftJoin('q.teamGame', 'tg')
->leftJoin('tg.Team', 't')
->getQuery()->getResult();
return array('entities' => $entities);
}
template:
{% extends "::layout.html.twig" %}
{% block content %}
<h1>Game plan</h1>
{% for entity in entities %}
{{ entity.place }}<br />{{ entity.group.name }}<br />
{% endfor %}
{% endblock content %}
You can achieve this by adding the ->select("q, g")
Related
I have problem to render view for creating new entity and can't find existing problem here being answered so I am going to ask...
My app has entity X that belongs to one entity Y and can have many entities Z.
When console runs, it executes well with all those relations.
php app\console doctrine:schema:update --force,
After crud generating for entity X, listing page shows fine, but page for creating new record throws following exception:
An exception has been thrown during the rendering of a template
("Warning: call_user_func_array() expects parameter 1 to be a valid
callback, class 'Symfony\Bridge\Twig\Extension\FormExtension' does not
have a method 'renderer->humanize' in
%path_to_app%\app\cache\dev\twig\16\16033db1d32d7d10db7a0d24db2f49938a4b2e9a63d231d90bf70d1969563fd0.php
line 880") in form_div_layout.html.twig at line 232.
What could be the problem?
Update 1:
Exception's trigger lays in twig file where data is passed from controller.
At {{ form_widget(form) }}
Update 2:
//controller's method
/**
*
*
* #Route("/new", name="class_new")
* #Template()
*/
public function newAction()
{
$entity = new Class();
$form = $this->createForm(new ClassType(), $entity);
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
//Form class
class ClassType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Admin\MainBundle\Entity\Class'
));
}
public function getName()
{
return 'admin_mainbundle_classtype';
}
}
// view
<form action="{{ path('class_create') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<p>
<button type="submit">Create</button>
</p>
</form>
Try to empty the cache : php bin/console cache:clear and rerun your command.
If problem persit: look at in your controller if you are used a undefined function for exemple renderer->humanize and look layout.html.twig at line 232.
I don't see any problem in your controller and view.
So i tried to look for in form_div_layout.html.twig file and i found that function humanize is used there and the exception says that function isn't defined.
So can you update your project by : composer install
form_div_layout.html.twig :
{%- block form_label -%}
{% if label is not same as(false) -%}
{% if not compound -%}
{% set label_attr = label_attr|merge({'for': id}) %}
{%- endif -%}
{% if required -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif -%}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ translation_domain is same as(false) ? label : label|trans({}, translation_domain) }}</label>
{%- endif -%}
{%- endblock form_label -%}
{%- block button_label -%}{%- endblock -%}
I solved this few weeks ago but now I spotted time for answering.
This was giving me headache before moving the app version from 2.1 to 2.8. Nowadays it works well.
I am building a project in Symfony 2.3 using Twig. I want to add a class to the form row block. I am using a form theme file which contains:
{% block form_row %}
<div class="form-row">
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_errors(form) }}
</div>
{% endblock %}
Now some of my form rows I want to add an extra class form-row-split. I can't figure out how to do this properly. The way I have it almost-working is:
{% block form_row %}
{% set attr = attr|merge({'class': 'form-row' ~ (attr.class is defined ? ' ' ~ attr.class : '') ~ (errors|length > 0 ? ' error' : '')} ) %}
<div {{ block('widget_container_attributes') }}>
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_errors(form) }}
</div>
{% endblock %}
(Note, I've left the error class logic in there too as that needs to stay).
Then in the form builder:
$builder
->add('first_name', 'text', array(
'attr' => array(
'class' => 'form-row-split'
)
));
This almost works but it adds this class everywhere and also adds the widget id to the row!
<div id="myform_first_name" class="form-row form-row-split">
<label for="myform_first_name">First name</label>
<input id="myform_first_name" class="form-row-split" type="text" name="myform[first_name]">
</div>
I can think of a few potential solutions but none of them are pretty or straight forward. Surely there must be a simple way of doing this?
There is a fairly simple solution to this problem actually. I just needed a form type extension to extend the base form type to allow an extra available option: http://symfony.com/doc/2.3/cookbook/form/create_form_type_extension.html
Following through the example in the docs, I created a new form type extension:
// src/Acme/FrontendBundle/Form/Extension/FormTypeExtension.php
namespace Acme\FrontendBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* Class FormTypeExtension
* #package Acme\FrontendBundle\Form\Extension
*/
class FormTypeExtension extends AbstractTypeExtension
{
/**
* Extends the form type which all other types extend
*
* #return string The name of the type being extended
*/
public function getExtendedType()
{
return 'form';
}
/**
* Add the extra row_attr option
*
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'row_attr' => array()
));
}
/**
* Pass the set row_attr options to the view
*
* #param FormView $view
* #param FormInterface $form
* #param array $options
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['row_attr'] = $options['row_attr'];
}
}
Then I registered the service in my bundle...
<!-- Form row attributes form extension -->
<service id="acme.form_type_extension" class="Acme\FrontendBundle\Form\Extension\FormTypeExtension">
<tag name="form.type_extension" alias="form" />
</service>
Since every widget extends the base form type this then allows me to pass this new row_attr option through on any field, eg:
$builder
->add('first_name', 'text', array(
'row_attr' => array(
'class' => 'form-row-split'
)
));
Then the twig overrides to make use of the new row_attr option:
{% block form_row %}
<div {{ block('form_row_attributes') }}>
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_errors(form) }}
</div>
{% endblock form_row %}
{% block form_row_attributes %}
{% spaceless %}
{% for attrname, attrvalue in row_attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
{% endspaceless %}
{% endblock form_row_attributes %}
And it's done!
(For completeness, my full twig override still merges in the form-row and error classes in like so:
{% set row_attr = row_attr|merge({'class': 'form-row' ~ (row_attr.class is defined ? ' ' ~ row_attr.class : '') ~ (errors|length > 0 ? ' error' : '')} ) %}
.. but thats not really necessary for answering my own question :P )
Docs say: you always able to pass attr to rendered element:
{{ form_start(form, {'attr': {'class': 'your-class'}} ) }}
{{ form_label(form, {'attr': {'class': 'your-class'}}) }}
{{ form_widget(form, {'attr': {'class': 'your-class'}}) }}
{{ form_errors(form, {'attr': {'class': 'your-class'}}) }}
{{ form_end(form) }}
Below is a clone of answer by #lopsided but with changes reflecting latest Symfony structure changes (v. 2.7+):
There is a fairly simple solution to this problem actually. I just needed a form type extension to extend the base form type to allow an extra available option: http://symfony.com/doc/master/form/create_form_type_extension.html
Following through the example in the docs, I created a new form type extension:
// src/Acme/FrontendBundle/Form/Extension/FormTypeExtension.php
namespace Acme\FrontendBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class FormTypeExtension
* #package Acme\FrontendBundle\Form\Extension
*/
class FormTypeExtension extends AbstractTypeExtension
{
/**
* Extends the form type which all other types extend
*
* #return string The name of the type being extended
*/
public function getExtendedType()
{
return FormType::class;
}
/**
* Add the extra row_attr option
*
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'row_attr' => []
));
}
/**
* Pass the set row_attr options to the view
*
* #param FormView $view
* #param FormInterface $form
* #param array $options
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['row_attr'] = $options['row_attr'];
}
}
Then I registered the service in my bundle...
<!-- Form row attributes form extension -->
<service id="acme.form_type_extension" class="Acme\FrontendBundle\Form\Extension\FormTypeExtension">
<tag name="form.type_extension" alias="form" extended_type="Symfony\Component\Form\Extension\Core\Type\FormType" />
</service>
Since every widget extends the base form type this then allows me to pass this new row_attr option through on any field, eg:
$builder
->add('first_name', TextType:class, [
'row_attr' => [
'class' => 'form-row-split'
]
]);
Then the twig overrides to make use of the new row_attr option:
{% block form_row %}
<div {{ block('form_row_attributes') }}>
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_errors(form) }}
</div>
{% endblock form_row %}
{% block form_row_attributes %}
{% spaceless %}
{% for attrname, attrvalue in row_attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
{% endspaceless %}
{% endblock form_row_attributes %}
And it's done!
(For completeness, my full twig override still merges in the form-row and error classes in like so:
{% set row_attr = row_attr|merge({'class': 'form-row' ~ (row_attr.class is defined ? ' ' ~ row_attr.class : '') ~ (errors|length > 0 ? ' error' : '')} ) %}
.. but thats not really necessary for answering my own question :P )
What I did was simpler (though maybe a bit less clean?).
Pass the class for the form row via a field's "data" attribute :
// template.html.twig
{{ form_start(form) }}
{{ form_row(form.field, {'attr': {'data-row-class': 'my-row-class'} }) }}
{{ form_end(form) }}
And then handle it in the form theme template this way :
// form-theme.html.twig
{% block form_row -%}
{% set row_class = attr['data-row-class'] | default('') %}
<div class="{{ row_class }}">
{{- form_label(form) -}}
{{- form_widget(form) -}}
{{- form_errors(form) -}}
</div>
{%- endblock form_row %}
Which gives this :
<form name="formName" method="post">
<div class="my-row-class">
<label for="formName_field">Field label</label>
<input type="text" id="formName_field" name="formName[field]" data-row-class="my-row-class">
</div>
</form>
I would like auto select value from session on radio button from twig. Unfortunately following code doesn't work for me.
In my twig template
{{ form_row(reg_form.sex, {'data' : 2}) }}
My form field type (User::SEX_MALE = 1, User::SEX_FEMALE = 2)
<?php
namespace FWM\CoreBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use FWM\CoreBundle\Entity\User;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* A form field for selecting user's sex
*/
class SexType extends AbstractType
{
/**
* {#inheritDoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'choices' => array(
User::SEX_MALE => 'label.form.male',
User::SEX_FEMALE => 'label.form.female'
),
'label' => 'label.form.sex',
'expanded' => true,
]);
}
/**
* {#inheritDoc}
*/
public function getParent()
{
return 'choice';
}
/**
* {#inheritDoc}
*/
public function getName()
{
return 'user_sex';
}
}
And my display customization:
{% block form_row %}
{% set error = false %}
{% if errors %}
{% set error = true %}
{% set attr = attr|merge({'class' : attr.class|default('') ~ ' error'}) %}
{% endif %}
{{ form_widget(form, {'attr' : attr, 'error': error}) }}
{% endblock form_row %}
{% block choice_widget %}
{% spaceless %}
{% if expanded %}
{% set attr = attr|merge({'class' : attr.class|default('') ~ ' radio-row'}) %}
<div {{ block('widget_container_attributes') }}>
{{dump(form)}}
{% for child in form %}
<span class="unbreakable">{{ form_widget(child) }} {{ form_label(child) }}</span>
{% endfor %}
</div>
{% else %}
...
If I add "data => 2" to setDefaults(...), field female becomes selected, but I can't find way to make it work by passing value from twig. Could someone help me please?
#qooplmao wrote in a comment:
By the time the form is available in the twig then everything that is or was going to happen to it should have happened. You could set your default in the object class $this->createFormBuilder(Object, {your options}) and then set it or you could hard code it in your entity.
When I've created a form:
$builder = $this->createFormBuilder();
$form = $builder->add( 'add', 'button')->getForm();
and render it:
<div><button type="button" id="form_add" name="form[add]">Add</button></div>
the attributes type, id and name are created.
I want to erase this attributes but I don't know how to do it. I've tried to do:
$builder = $this->createFormBuilder();
$form = $builder->add( 'add', 'button', array( 'attr' => array() ) )->getForm();
without any success.
How could I do it?
Greetings and thanks
I messed around with this for a while and the closest I could get was to have them render with empty attributes. However, that's because the project I tested with is Symfony 2.0, and in that version it's impossible to completely remove the attributes since Symfony\Component\Form\FormView::$vars is private.
However, in Symfony 2.1 and later, that same property is public so you should be able to modify (or delete) the attributes/vars directly without being constrained by the FormView api.
First, create your own type to represent this "naked button"
src/Your/Bundle/Form/NakedButtonType.php
<?php
namespace Your\Bundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
class NakedButtonType extends AbstractType
{
/**
* (non-PHPdoc)
* #see Symfony\Component\Form.FormTypeInterface::getName()
*/
public function getName()
{
return "naked_button";
}
/**
* (non-PHPdoc)
* #see Symfony\Component\Form.AbstractType::getParent()
*/
public function getParent(array $options)
{
return 'button';
}
/**
* (non-PHPdoc)
* #see Symfony\Component\Form.AbstractType::buildViewBottomUp()
*/
public function buildViewBottomUp(FormView $view, FormInterface $form)
{
// Symfony 2.0
// This will still render the attributes, but they will have no value
$view->set('id', null);
$view->setAttribute('type', null);
// Symfomy >= 2.1
// This *should* remove them completely
unset( $view->vars['id'] );
unset( $view->vars['attr']['type'] );
}
}
Now, tell the service container how to build your type
app/config/config.yml
services:
form.type.naked_button:
class: Your\Bundle\Form\NakedButtonType
tags:
- {name: form.type, alias: naked_button}
Then update your parent form to use your new type instead of the ootb "button" type.
$builder = $this->createFormBuilder();
$form = $builder->add( 'add', 'naked_button')->getForm();
All of that being said...
If you want these buttons w/o any attributes, why not just put them like that directly into your view?
<form>
{{ form_errors(form) }}
{{ form_rest(form) }}
<div>
<button>Add</button>
</div>
</form>
All of this custom type nonsense seems like alot of overhead to render something you clearly don't need Symfony to manage for you.
While not a good idea, I will help you load the gun and shoot yourself in the foot :-)
Create a new Resources/views/Form/fields.html.twig file, and put the following in it:
{% block widget_attributes %}
{% spaceless %}
id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
{% for attrname, attrvalue in attr %}{% if attrname in ['placeholder', 'title'] %}{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}" {% else %}{{ attrname }}="{{ attrvalue }}" {% endif %}{% endfor %}
{% endspaceless %}
{% endblock widget_attributes %}
If you really, really want to remove all the attributes on there, you can remove the {% for attrname ... %} line. That will remove the attributes from all form fields. If you add some logic, you can have it apply to just specific fields.
Next step, you need to register your fields helpers. In your app/config/config.yml file, add the following line:
twig:
form:
resources:
- 'SomeBundle:Form:fields.html.twig'
Im new to symfony and what im trying is next:
Select everything from the table and count the number of rows.
Access and display this informations in a twig template.
This is part from my code in the controler dedicated to fetch data from datatabase :
.
.
.
$em=$this->getDoctrine()->getManager();
$query=$em->createQuery('SELECT b,COUNT(b.id) FROM AcmeWebBundle:baza b ORDER BY b.id DESC');
$users = $query->getResult();
if (!$em) {
throw $this->createNotFoundException('Something went wrong!');
}
return $this->render('AcmeWebBundle:Default:index.html.twig',array('users'=>$users));
}
in the table named baza i have the fields: id,username,date..etc
And part from the twig file named index.html.twig
{% extends 'AcmeWebBundle:Default:master.html.twig' %}
{% block body %}
<h1> something</h1><br></br>
{% for user in users %}
{{ ...how to access to the number of rows and other data...}}
{% endfor %}
{% endblock %}
Queries:
$query = $this->createQueryBuilder()
->from('AcmeWebBundle:baza', 'b')
->getQuery();
$user = $query->select('b')
->getQuery()
->getResult();
$total = $query->select('COUNT(b)')
->getQuery()
->getSingleScalarResult();
.....
return $this->render('AcmeWebBundle:Default:index.html.twig',array('users' => $users, 'count' => $total));
Template:
{% extends 'AcmeWebBundle:Default:master.html.twig' %}
{% block body %}
<h1> something</h1><br></br>
{% for user in users %}
{{ user.id }}
{{ user.name }}
{% endfor %}
{% endblock %}
Total users: {{ count }}
Where id and name fields in your DB.
You could try the following:
{{ user.id }}
{{ user.username }}
{{ user.date }}
...etc...