How to fix 'Variable does not exist' when using FormBuilder? - symfony

I've worked through a few of the Forms-Tutorials on the Symfony-Page (especially How to Embed a Collection of Forms, How To use a Form without a Dataclass & CollectionType Field ).
I'm trying to show a form with multiple lead partners which can be edited and submitted back to the system.
But i get a Twig_Runtime_Error saying: ''Variable "lead_partners" does not exist''.
My Twig:
{% block content %}
<div>
{{ form_start(form) }}
{% for partner in lead_partners %}
{{ form_row(partner.name) }}
{% endfor %}
{{ form_end(form) }}
</div>
{% endblock content %}
My Controller Code:
public function overview(Request $request, \App\Utility\LeadPartnerLoader $LeadPartnerLoader)
{
$leadPartnerList = $LeadPartnerLoader->loadAll();
$form = $this->createFormBuilder($leadPartnerList)
->add('lead_partners', CollectionType::class, [
'entry_type' => LeadPartnerFormType::class,
])->getForm();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid())
{
$data = $form->getData();
}
return $this->render(
'lead_partner_overview2.html.twig',
[
'form' => $form->createView()
]);
}
And the Form Type (LeadPartnerFormType):
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => LeadPartner::class,
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', HiddenType::class)
->add('name', TextType::class);
}
$leadPartnerList is of type array.
What am i doing wrong/missing here?
Kind Regards

It seems your action overview soesn't return the lead_partners variable you use in your template.
You can try to do this
return $this->render(
'lead_partner_overview2.html.twig',
[
'form' => $form->createView(),
'lead_partners' => $leadPartnerList, // I gess that's the list you want to loop ?
]);

Related

Problems having two different forms in the same twig file

I have been experiencing problems with embedding a controller that creates a form where you can upload files. When the controller is rendered in certain parts of the twig file, I get this error:
An exception has been thrown during the rendering of a template ("Expected argument of type "Symfony\Component\HttpFoundation\File\UploadedFile", "string" given").
This is strange since in other parts of the same twig file, the expected argument is given without problems. The problem seems to be another form in the same twig file that doesn't play nice with my embedded controller form.
The part that seems to cause the problem:
<div id="payment_checkout_form">
{% if cId and shippingRegionId %}
{% set savedPath =path('cart_set_shipping', {'store_id': webstore.id, 'shippingRegion': shippingRegionId,'cId':cId}) %}
{{ form_start(form, {'attr': {'id': 'form_checkout','data-url':savedPath}}) }}
{% else %}
{{ form_start(form, {'attr': {'id': 'form_checkout'}}) }}
{% endif %}
{{ render(url('passport')) }}
Relevent part of my PassportType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', 'file', array('label' => false) , [
'multiple' => true,
'label' => '',
'attr' => [
'accept' => 'image/*',
'multiple' => 'multiple'
]
]
)
->add('confirm', 'submit');
}
public function configureOptions(OptionsResolver $resolver){
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Passport',
));
}
Relevent part of my Passport entity:
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
/**
* Sets file.
*
* #param Symfony\Component\HttpFoundation\File\UploadedFile $file
*/
public function setFile(UploadedFile $file = null) {
$this->file = $file;
}
Relevent part of my Passport controller
/**
* #Route("/passport", name="passport")
*/
public function createPassportAction(Request $request)
{
$request = $this->get('request_stack')->getMasterRequest();
$passport = new Passport();
$passport->setName('default');
$form = $this->createForm(new PassportType(), $passport);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$files = $request->files->get('passportPhoto');
if (!empty($files)) {
$this->uploadFile($files);
}
}
return $this->render('passport.html.twig', [
'form' => $form->createView(),
'isFormSubmitted' => $form->isSubmitted(),
'passportImages' => $this->getDoctrine()->getRepository('AppBundle\Entity\Passport')->findAll(),
]);
}
{{ render(url('passport')) }} is the embedded controller that renders the file upload form. If I put the{{ render(url('passport')) }} above the form_start of the other form everything works.
Answering my own question:
embedding a form inside another form like I'm trying to do in the question by using render is not possible. I fixed my problem by first removing the render call of my embedded passport form and making my passport type a sub type of the type that is used in the checkout form like this:
public function buildForm(FormBuilderInterface $builder, array $options){
$builder
...
->add('passport', new PassportType(), array(
'required' => true
))
...
}
I still wanted to have the controller of the passport part of my form to be in it's own file. To achieve this I called my passport controller inside of the checkout controller using the forward method like this:
$files = $request->files->get('order')['passport_id'];
$store_id = $request->attributes->get('store_id');
$this->forward('AppBundle\Controller\PassportController::uploadFile',
[ 'files' => $files, 'store_id' => $store_id ]);

Some mandatory parameters are missing ("user") to generate a URL for route

My motivation is to edit values displayed in this edit form. But when I press edit button it throws out this error. I can't figure it out. Can anyone help what is missing in my code?
An exception has been thrown during the rendering of a template ("Some
mandatory parameters are missing ("user") to generate a URL for route
"sokosimu_editor_edit_editoruser".") in
SokosimuEditorBundle:User:editUser.html.twig at line 7. 500 Internal
Server Error - Twig_Error_Runtime
Router
sokosimu_editor_edit_editoruser:
path: /edit/editoruser/{user}
defaults: {_controller:SokosimuEditorBundle:Editor:editEditorUser}
requirements:
_method: GET|POST
Controller
public function editEditorUserAction(User $user,Request $request){
$form = $this->createForm(new EditUserType(),$user);
//2. handle the submit (will happen on POST)
$form->handleRequest($request);
if($form ->isValid() && $form->isSubmitted()){
}
$em = $this->get('doctrine')->getManager();
$editUser = $user ->getEditoruser();
return $this->render('SokosimuEditorBundle:User:editUser.html.twig', array(
'form' => $form->createView()
));
}
View
{% block title %}Edit User{% endblock%}
{% block body %}
<form action="{{ path('sokosimu_editor_edit_editoruser') }}" method="post" {{ form_enctype(form) }} class="formedit">
{{ form_errors(form) }}
{{ form_row(form.alias)}}
{{ form_row(form.email) }}
{#{{ form_row(form.password) }}#}
{{ form_row(form.mobile) }}
{{ form_row(form.submit) }}
{{ form_rest(form) }}
</form>
{% endblock %}
Form
<?php
namespace Sokosimu\EditorBundle\Form\Type;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class EditUserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('alias','text',array('required'=>false));
$builder->add('email', 'email',array('required'=>true));
// $builder->add('password','password',array('required'=>true));
$builder->add('mobile','text',array('required'=>false));
$builder->add('submit', 'submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Sokosimu\UserBundle\Entity\User'
// 'data_class' => NULL
));
}
public function getName()
{
return 'editUser';
}
}
You need to pass user in the path:
<form action="{{ path('sokosimu_editor_edit_editoruser', {'user': user}) }}" method="post" {{ form_enctype(form) }} class="formedit">
And in controller render the twig with user:
return $this->render('SokosimuEditorBundle:User:editUser.html.twig', array(
'form' => $form->createView(),
'user' => $user
));
Fix route to
sokosimu_editor_edit_editoruser:
path: /edit/editoruser/{userId}
defaults: {_controller:SokosimuEditorBundle:Editor:editEditorUser}
requirements:
_method: GET|POST
Fix controller to
public function editEditorUserAction(Request $request, $userId)
{
$user = $this->getDoctrine()->getRepository('SokosimuEditorBundle:User')->find($userId);
$form = $this->createForm(new EditUserType(), $user);
//2. handle the submit (will happen on POST)
$form->handleRequest($request);
if ($form->isValid() && $form->isSubmitted()) {
$em = $this->get('doctrine')->getManager();
$editUser = $user->getEditoruser();
}
return $this->render('SokosimuEditorBundle:User:editUser.html.twig', array(
'form' => $form->createView()
));
}
With the help from #panche14, I have modified the code a bit.Answer from #panche14 returned object but the form #param expected to be string or integer.
return $this->render('SokosimuEditorBundle:User:editUser.html.twig',
array('form' => $form->createView(),
'user' => $user ->getId();
));
Also add this in twig file:
{'user': user}
as specified by #panche14
Now, the edit button works fine as desired.

How to render collections of forms

I have problem with rendering forms in Twig. I'm trying to embed a collection of forms. When I render the collection, it is not shown, while it is shown the name of form. The aim was to make the forms with an add button to add at runtime the form for each element of the collection. I get a look to the Symfony Docs and I think I followed it step by step.
This is my controller:
function new_resultAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$test = $em->getRepository('LadelaOdeskTesterBundle:Test')->find($id);
$categories =
$em->getRepository('LadelaOdeskTesterBundle:Category')->findByTest($test);
if (!$test) {
throw $this->createNotFoundException('Unable to find Test entity.');
}
$resultCategory = new Category();
$form = $this->createForm(new CategoryType() , $resultCategory);
$request = $this->getRequest();
if ('POST' === $request->getMethod()) {
$form->bindRequest($request);
if ($form->isValid()) {
$em->persist($resultCategory);
$em->flush();
$this->get('session')->setFlash('success', 'New result Categories were
saved!');
return $this->redirect($this->generateUrl('questions', array(
'id' => $resultCategory->getId(),
)));
}
}
return array(
'test' => $test,
'categories' =>$categories,
'form' => $form->createView(),
);
}
My forms:
class ResultCategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('value', 'integer');
$builder->add('category', 'entity', array(
'class' => 'Ladela\OdeskTesterBundle\Entity\Category',
'query_builder' => function ($repository) { return
$repository->createQueryBuilder('p')->orderBy('p.name', 'ASC'); },
'property' => 'name' ,
'expanded' => false ,
'multiple' => false , ));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Ladela\OdeskTesterBundle\Entity\ResultCategory'
));
}
public function getName()
{
return 'ResultCategory';
}
}
class CategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('resultCategories','collection', array(
'type' => new ResultCategoryType(),
'allow_add' => true,
'by_reference' => false,
'prototype' => true,
))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Ladela\OdeskTesterBundle\Entity\Category'
));
}
public function getName()
{
return 'category';
}
}
And my twig file:
<form method="post" action="{{ path('questions',{'id': test.id }) }}" {{
form_enctype(form) }} >
<ul class="tags" data-prototype="{{
form_widget(form.resultCategories.vars.prototype)|e
}}">
{# iterate over each existing tag and render its only field: name #}
{% for ResultCategory in form.resultCategories %}
<li>{{ form_row(ResultCategory.category) }}</li>
{% endfor %}
Add a tag
</ul>
{{ form_rest(form) }}{# form.items's prototype is rendered twice #}
{{ form_errors(form) }}
<input type="submit" value ="add" />
</form>
{% block javascripts %}
<script type="text/javascript">
// Get the div that holds the collection of tags
var collectionHolder = $('ul.tags');
// setup an "add a tag" link
var $addTagLink = $('Add a tag');
var $newLinkLi = $('<li></li>').append($addTagLink);
jQuery(document).ready(function() {
// add the "add a tag" anchor and li to the tags ul
collectionHolder.append($newLinkLi);
$addTagLink.on('click', function(e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// add a new tag form (see next code block)
addTagForm(collectionHolder, $newLinkLi);
});
});
// Get the div that holds the collection of tags
var collectionHolder = $('ul.tags');
// setup an "add a tag" link
var $addTagLink = $('Add a tag');
var $newLinkLi = $('<li></li>').append($addTagLink);
jQuery(document).ready(function() {
// add the "add a tag" anchor and li to the tags ul
collectionHolder.append($newLinkLi);
$addTagLink.on('click', function(e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// add a new tag form (see next code block)
addTagForm(collectionHolder, $newLinkLi);
});
});
{% endblock %}
The collection of forms is not rendered since you don't initiate it! See the official docs. There are "dummy" tags object used to create the tag forms.

Render Individual Form Element in Symfony 2

I'm having trouble rendering individual form fields in a twig template from a Symfony 2 form. In the example below, I'm simply trying to render the first_name form field.
Also, form_errors never renders anything.
Here is my Form object:
namespace ABC\WebsiteBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class LoanApplication extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('first_name', 'text', array('required' => true));
}
public function getName()
{
return 'LoanApplication';
}
public function getDefaultOptions(array $options)
{
return array(
//'data_class' => 'Acme\TaskBundle\Entity\Task',
'csrf_protection' => true,
'csrf_field_name' => '_token',
// a unique key to help generate the secret token
'intention' => 'loan_application',
);
}
}
Here is the controller:
namespace ABC\WebsiteBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use JML\WebsiteBundle\Form\LoanApplication;
use JML\WebsiteBundle\QuickBase as QuickBase;
class ApplyController extends Controller
{
public function indexAction()
{
$form = $this->createForm(new LoanApplication());
return $this->render('ABCWebsiteBundle:Apply:index.html.twig', array(
'form' => $form->createView(),
));
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
// perform some action, such as saving the task to the database
//return $this->redirect($this->generateUrl('task_success'));
}
}
}
}
And the twig:
<form action="{{ path('apply') }}" method="post" {{ form_enctype(form) }}>
<pre>
{{ dump(form_errors(form)) }} // always empty
</pre>
<div>
{{ form_label(form.first_name) }} // this renders
{{ form_widget(form.first_name) }} //empty
{{ form_row(form.first_name) }} //empty
</div>
<input type="submit" formnovalidate/>
</form>

Forms symfony2, display my created form in Symfony2

i need your help please , I want to display my created form in Symfony2. I want to display my created form 92 times becouse i have 92 numbers in my database(every number is a form) , i didn't know how to do it here is my code:
controller:
class DefaultController extends Controller
{
public function QuestionsAction(Request $request)
{
$questions = $this->getDoctrine()->getEntityManager()
->getRepository('Tests\TestsPhpBundle\Entity\Question')
->findAll();
$task = new Question();
$forms = $this->createForm(new QuestionType(), $task);
if ($request->getMethod() == 'POST') {
$forms->bindRequest($request);
if ($forms->isValid())
{
$em = $this->getDoctrine()->getEntityManager();
$em->persist($task);
$em->flush();
}
}
{
return $this->render('TestsTestsPhpBundle:Default:index.html.twig', array(
'questions' => $questions,
'forms' => $forms->createView()
));
}
}
}
my form file:
class QuestionType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('categories', null, array('required' => false,
))
->add('text', 'entity', array(
'class' => 'TestsTestsPhpBundle:Question',
'query_builder' => function($repository) {
return $repository->createQueryBuilder('p')->orderBy('p.id', 'ASC'); },
'property' => 'text'))
;
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Tests\TestsPhpBundle\Entity\Question',);
}
public function getName()
{
return 'question';
}
}
my twig file:
{% block content %}
<h2>Questions</h2>
{% for question in questions %}
<dl>
<dt>Number</dt>
<dd>{{ question.number }}<dd>
{% for form in forms %}
{{ form_row(forms.categories) }}
{{ form_row(forms.text) }}
</dl>
{% endfor %}
<hr />
{% endfor %}
{% endblock %}
I recommend to read capter: Embedding Controller
http://symfony.com/doc/2.0/book/templating.html
<div id="sidebar">
{% render "AcmeArticleBundle:Article:recentArticles" with {'max': 3} %}
</div>
You can make a for loop within Twig Template and call an action (with parameter if needed) where you render the form. -> QuestionsAction in your case.

Resources