Symfony2 forms are rendered empty - forms

I've just started trying to build forms with Symfony2.4.2 and having a VERY frustrating time. I have successfully managed to build the example found in the book chapter 12. I've also tried to build essentially the same form in another project, in another bundle and always seems to end up with an empty form:
<html>
<head></head>
<body>
<form action="" method="post" name="form"> </form>
</body>
</html>
The code to create this:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use DMV\form3Bundle\Entity\Task;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
public function newAction(Request $request)
{
// create a task and give it some dummy data for this example
$task = new Task();
$task->setTask('Write a blog post');
$task->setDueDate(new \DateTime('tomorrow'));
$form = $this->createFormBuilder($task)
->add('task', 'text')
->add('dueDate', 'date')
->add('save', 'submit')
->getForm();
return $this->render('DMVform3Bundle:Default:new.html.twig', array('form' => $form->createView(),));
}
}
new.html.twig:
{{ form(form) }}
I've tried tried delving into the "$form" at a breakpoint at the "return $this->render..." line that is suppose to render the form and I DO see the form elements texts in the structure but it is a very large and complex structure and I'm not sure what I should see exactly.
Any suggestions would be appreciated.

You can simply render form in your new.html.twig template like:
{# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #}
{{ form(form) }}
But if you use Symfony version < 2.3, so try to use something that:
{# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #}
<form action="{{ path('task_new') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" />
</form>

Related

Create form based on EntityType with option to add quantity

I'm trying to setup a Symfony form that will allow a user to select a number of elements adding the wished quantity. I would like to be able to have a FormType which would be somewhere between an EntityType and the IntegerType. Meaning I need to have a list of elements based on a query_builder to select only part of my products, but I don't just want to be able to select the product but say how many I want of a given number of products.
I've been able to create a form based on the options I send. For each product in my array I add an IntegerType field to my form using the builder. This allows me to show a list of products and ask the client the number of elements he wants.
Now the problem I have is adding detailed data from the product in the list as I don't know the forms field names I can't interact with the label. If I could add something allowing me to say that the 'label' could show as raw html, I could concatenate the wished data in the label.
Here is my current form:
class OfferRequestStepMultipleHardwareType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// instead of haveing set fields I create them based on the $option['step']->getProducts() data
foreach ($options['step']->getProducts() as $product){
$builder->add($product->getId().'-qty', IntegerType::class, [
'mapped' => false,
'attr' => [
'value' => 0,
'class' => 'longlist',
'min' => 0
],
'row_attr' => [
'class' => 'longlist'
],
'label' => $product->getNumber() // ideally I would do some thing like '<div>'.$product->getNumber().'</div><div>'.$product->getDescription().'</div>' and then show it as raw in the form template
]);
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => OfferRequest::class,
'step' => StepHardware::class,
]);
}
}
The problem is this generates code a bit like this:
<div id="offer_request_step_multiple_hardware">
<div class="longlist"><label for="offer_request_step_multiple_hardware_27-qty" class="required">Product 1</label><input type="number" id="offer_request_step_multiple_hardware_27-qty" name="offer_request_step_multiple_hardware[27-qty]" required="required" value="0" class="longlist"
min="0"></div>
<div class="longlist"><label for="offer_request_step_multiple_hardware_28-qty" class="required">Product 2</label><input type="number" id="offer_request_step_multiple_hardware_28-qty" name="offer_request_step_multiple_hardware[28-qty]" required="required" value="0" class="longlist"
min="0"></div>
<div class="longlist"><label for="offer_request_step_multiple_hardware_29-qty" class="required">Product 3</label><input type="number" id="offer_request_step_multiple_hardware_29-qty" name="offer_request_step_multiple_hardware[29-qty]" required="required" value="0" class="longlist"
min="0"></div>
<div class="longlist"><label for="offer_request_step_multiple_hardware_30-qty" class="required">Product 4</label><input type="number" id="offer_request_step_multiple_hardware_30-qty" name="offer_request_step_multiple_hardware[30-qty]" required="required" value="0" class="longlist"
min="0"></div><input type="hidden" id="offer_request_step_multiple_hardware__token" name="offer_request_step_multiple_hardware[_token]" value="PZaPfxKNSV-TjftRgjAw1K8XCUr7Dvkrp57kWTMBJ64"></div>
I've also tried to create a form theming in the template to change the way the Integer widget show with this:
{% form_theme form _self %}
{% block question %}
<h1>{{ offer.lastStep.Question }}</h1>
{% endblock %}
{% block integer_widget %}
<div class="name_row">
{{ form_label(form)|raw }}
{{ form_errors(form) }}
{{ form_widget(form) }}
{{ form_help(form) }}
</div>
{% endblock %}
Without any success as when I concatenate and try to add the filter "raw" to it, the code is still changed autoescaped. The problem is then I've found information on how to set a specific label for a specific field of a form, but again I generate the form on the go and have no way of knowing the field names (like described here). Any suggestions on how to have this work?
Ideally I would like to be able to create a FormType based on the EntityType which would allow to add an Integer instead of selecting the Entity elements...
Any help would be nice!
Labels in Symfony forms are escaped at some point before the rendering of the template, so applying the twig raw filter won't prevent html entities from being escaped.
What you can do is create a new twig filter, to apply the php function html-entity-decode (following code untested):
Twig/HtmlDecodeExtension.php
<?php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class HtmlDecodeExtension extends AbstractExtension
{
public function getFilters()
{
return [
new TwigFilter('htmldecode', [$this, 'htmlDecode']),
];
}
public function htmlDecode($value)
{
return html_entity_decode($value);
}
}
If you use the default configuration with services autowiring, you don't have to register the new extension; in the other case, do it in config/services.yaml
Now you can use the filter in your form template instead of raw, and put whatever html you like in the label:
{% form_theme form _self %}
{% block question %}
<h1>{{ offer.lastStep.Question }}</h1>
{% endblock %}
{% block integer_widget %}
<div class="name_row">
{{ form_label(form)|htmldecode }}
{{ form_errors(form) }}
{{ form_widget(form) }}
{{ form_help(form) }}
</div>
{% endblock %}

zend 2 -using Zend Forms in partial view helper

I have a form that is repeated over several different modules.
I would like to avoid repeating the same process over and over again and want to render the form once (in my application module) and then simply use a partial view script to call it wherever I wish like this;
<?php echo $this->partial('partialLayout/advertForm'); ?>
Following the advice here it would be pretty straightforward to do this if I simply created a HTML form in the partial script and then called it.
However, I want to use Zend Forms. Bearing in mind that zend form are loaded onto the page via the controller- how do I get around this.
i guess that the crux of the question is - how do you call a Zend Form in another module using a partial view script.
I did something like that with a ViewHelper. My solution is posted here, in Zend Forums.
There it is.
The code ViewHelper :
<?php
/**
* View helper to return the HTML code of the login form.
*
* #filesource LoginForm.php
* #encodage UTF-8
* #author DAFAP Informatique - Alain Pomirol
* #date 10 nov. 2015
* #version 2015-1
*/
namespace Login\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\View\Model\ViewModel;
use Login\Form\LoginForm as Formulaire;
class LoginForm extends AbstractHelper implements ServiceLocatorAwareInterface
{
protected $sm;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->sm = $serviceLocator;
return $this;
}
public function getServiceLocator()
{
return $this->sm;
}
public function __invoke()
{
$form = new Formulaire();
$layout = new ViewModel(array(
'form' => $form
));
$viewRender = $this->getServiceLocator()->getServiceLocator()->get('ViewRenderer');
$layout->setTemplate('login/index/index.phtml');
return $viewRender->render($layout);
}
}
The statement in module.config.php in Login module :
'view_helpers' => array(
'invokables' => array(
'loginForm' => 'Login\View\Helper\LoginForm'
)
),
Use in view of the application module :
'view_helpers' => array(
'invokables' => array(
'loginForm' => 'Login\View\Helper\LoginForm'
)
),
It's a common problem! Forms can really be a slow-down with ZF2.
I use Twig (recommended) but you can port this approach to plain old ZF2 templates too.
Here's one such template I use nearly everywhere:
horizontal_form.twig
{# render rows only, not the form tag #}
{% do form.prepare() %}
{% for f in form %}
{% do f.setOption( 'twb-layout', 'horizontal' ) %}
{{ formRow( f ) }}
{% endfor %}
I've got a second with a slightly different approach to support a specific IdentifiableForm in my code:
identifiable_form.twig
<form id="{{ form.getAttribute('name') }}" name="{{ form.getAttribute('name') }}" action="{{ form.getAttribute('action') }}" class="form-horizontal" role="form">
<input type="hidden" name="class" value="{{ form.getAttribute('class') }}">
{% for f in form %}
{% do f.setOption( 'twb-layout', 'horizontal' ) %}
{% do f.setOption( 'twb-form-group-size', 'form-group-sm' ) %}
{{ formRow( f ) }}
{% endfor %}
<div class="hr-line-dashed"></div>
<button type="submit" class="btn btn-primary ladda-button" data-style="expand-right">Save</button>
</form>
With those two in the pocket, my usage looks like this:
In a twig template that should use a form
...include the template from the other:
<div class="panel-body">
{% set form = general_config_form %}
{% do form.prepare() %}
{% include 'application/generic/identifiable_form' %}
</div>
The controller action that operates that template looks like:
$vm = new ViewModel();
$vm->setTerminal( true );
$vm->setTemplate( 'application/admin/config/index' );
$sm = $this->getServiceLocator();
$fm = $sm->get( 'FormElementManager' );
$country = $config_mapper->get('general.country', true );
$general_config_form = $fm->get( GeneralConfigForm::class, [ 'country' => $country ] );
$general_config_form->setAttribute('action', '/admin-config/form-save' );
$vm->setVariable( 'general_config_form', $general_config_form );
In the end it's just a game of:
instantiating/loading the form in the action
setting the form as a variable in the ViewModel
including the "generic form template" from that action's actual template
On topic, if you hate rigging forms as much as I do, I made a little tool to save time here: https://github.com/Saeven/zf2-circlical-formtool
Second, if you use Bootstrap in your app, this form helper replacement really makes things look nice: https://github.com/neilime/zf2-twb-bundle
Good luck!

How can I render search results using Symfony?

I've created a form for searching data in the DB.
This is the form:
<form role="search" method="post" action="{{ path('search') }}">
<div>
<input type="text" placeholder="Cerca" name ="search">
<span>
<button type="submit"></button>
</span>
</div>
</form>
And of course I also have the action in the controller:
public function searchAction(Request $request)
{
$request = $this->getRequest();
$data = $request->request->get('search');
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery('SELECT a FROM AppBundle:Article a WHERE a.titolo LIKE :data')
->setParameter('data', $data);
$result = $query->getResult();
return $this->render('default/search.html.twig', array('result' => $result));
}
In this way, I can write in the field what I want to search, and submit the form. The form is submitted, but it renders the form again without any message or results.
If I want to render the results, do I have to create a results template where I use a for loop to render all the results?
How can I render the results?
You're already passing $results to the render function. So with the required code in your template it should work without much hassle:
E.g.
{% for result in results %}
<div>
// use result, e.g. {{ result.title }} or whatever your data has to offer
</div>
{% else %}
<em>no results found</em>
{% endfor %}

Render collection automatically in Symfony 2 using entity type form

I have a two entities: Products and Categories.
Each entity renders a custom form using the Symfony Form Builder .
I'm trying to include the Categories form inside the Products form using the collection field type. The include line looks like the following:
$builder->add('idCategory', 'collection', array('type' => new CategoryType());
It's working fine (according to the Symfony documentation). But I don't want to create the form with JavaScript, I want to have it rendered with the rest of the form without changing the twig template:
<form action="{{ path('product_create') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<button type="submit">Create</button>
</form>
Is it even possible? Any thoughts?
Do you know the number of categories you want to include in the products?
I found a workaround for this since it seems to be impossible to auto render the form without using JavaScript.
Instead of rendering the whole form at once, using {{ form_widget(form) }}, I'm rendering field by field and using {{ form_widget(form.categoy.vars.prototype) }} to render the Category collection. The template code looks like the following:
<div id="form">
{{ form_start(form) }}
{{ form_errors(form) }}
...
{{ form_row(form.name) }}
{{ form_row(form.price) }}
...
<h2>Categories</h2>
{{ form_row(form.idCategory) }}
{{ form_widget(form.idCategoryNew.vars.prototype) }}
...
<button type="submit">Create</button>
{{ form_end(form) }}
</div>
And the ProductType:
$builder
->add('name'))
->add('price'))
...
->add('idCategory', 'entity', array('class' => 'MyBundle\Entity\Category'))
->add('idCateogryNew', 'collection', array('type' => new CategoryType(), 'allow_add' => true))
...
EDIT:
I found a better workaround which consist in passing the collection form to the twig template. This way is easy to handle the post request after the form submission. If anyone want the code, please ask :)
EDIT 2:
Per #agapitocandemor request:
Inside your MainEntityController (ProductController in my case), search the method that renders the form (newAction in my case) and create the Entity form that you want to render:
public function newAction()
{
$entity = new Product();
$entityform = $this->createForm(new ProductType(), $entity);
$subentityform = $this->createForm(new CategoryType(), new Category);
return $this->render('MyBundle:Product:new.html.twig', array(
'entity' => $entity,
'entityform' => $entityform->createView(),
'subentityform' => $subentityform->createView()
));
}
Finally, in order to render the subentityform you just need to call {{ form_widget(subentityform) }} from the new template of your main entity.

Site-wide form with Symfony2?

I have simple form at all site pages: username, password, [Sign In]
I tried to make with with simple HTML, but I get
The CSRF token is invalid. Please try to resubmit the form
Idea to make form in each action seems bad. What is the good practice of doing site-wide forms?
You have to do it this way:
First, I guess you have some base template file like layout.html.twig and all other pages extend it. Eg:
// Resources/views/layout.html.twig
<doc ... bla blah>
<title>My site</title>
...(js, css)...
<body>
<div id="top">
{% render url("site_wide_form") %}
</div>
{% block content %}
{% endblock content %}
</body>
You need controller that will handle your form:
//Controller/SitewideController.php
/**
* #Route("/some/url/here", name="site_wide_form")
* #Template("yourbudle:folder:site_wide_form.html.twig")
*/
public function someAction()
{
..... your code for form, process submission etc ...
return ["form"=>$form->createView()] ;
}
and template file:
// site_wide_form.html.twig
<form action="{{ path("site_wide_form") }}" method="post">
{{ form_widget(form) }}
</form>
That's it. Read this to understand render tag: http://symfony.com/doc/2.2/book/templating.html#embedding-controllers
The CSRF token is missing. In your template (I assume you use Twig). You can tell Symfony2 to render all the remaining form elements using:
{{ form_rest(form) }}
Or you can render just the CSRF token:
{{ form_row(form._token) }}