Stuck on an annoying problem and I feel like I need another set of eyes.
For some reason I can't get this formbuilder generated field to be found by the controller in Symfony.
Here's the relevant piece of the controller
$barcode = $request->get('barcode');
$em = $this->getDoctrine()->getManager();
//this checks for whether an item still exists
$items = $em->getRepository('Bundlename:Items\Item')
->itemsNotDisposedByBarcode($barcode);
if ($items) { .... do stuff ...}
else { $this->get('bundle.flashbag')
->addError('Item not found.');
Nothing ever seems to be found.
I tested this by running the conditional off of $barcode so it's pretty certainly the twig or the form (in other words, I'm pretty certain that it's not itemsNotDisposedByBarcode, there appears to be nothing wrong with the query)
Here's what the formbuilder looks like:
class DisposeItemBarcodeType extends AbstractType
{
protected $editors = array();
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('barcode','text',
array('required' => false));
}
public function getName()
{
return 'bundle_items_item';
}
}
I keep thinking it might be the twig somehow, however it looks fine to my eyes; not sure if it's the formbuilder, or if I need to hack this apart and just use a regular form. Here's what I have for this:
{{ form_start(form, {'action': path('bundle_item_dispose_post'),'attr': {'id': 'dispose-item-form','novalidate': 'novalidate'}}) }}
{{ form_errors(form) }}
<section>
<div class="panel-body" id="barcode">
{{ form_row(form.barcode, {'attr': {'name':'barcode','class': 'barcode-field', 'autofocus': true}})}}
</div>
I have a feeling I'm missing something obvious but my eyes are not seeing it.
===
Edit: solved with help from below
Turns out formbuilder does some tokening, so I just needed to do this:
$barcode = $postData['bundle_items_item']['barcode'];
I think that the problem is that you wanna retrieve a POST variable not a GET, to get this try this please:
$postData = $request->request->all();
$barcode = $postData['barcode'];
Related
Im learning Symfony and I'm creating a CRUD app for practicing.
I want to implement a search function in the page where I list my db items. I was wondering what is the correct way to achieve this.
Right now, I have created a searchType and searchController with the next code:
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class searchController extends Controller
{
public function searchAction(){
$formulario = $this->createForm('AppBundle\Form\SearchType');
return $this->render('searchBar.html.twig', ['form' => $formulario->createView()]);
}
}
class SearchType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('key', ChoiceType::class,
['choices' => [
'Elegir Campo...' => 0,
'Modelo' => 1,
'Marca' => 2,
'Año' => 3,
'Propietario' => 4
]
])
->add('term', TextType::class)
->add('buscar', SubmitType::class)
;
}
}
I have another controller called itemController, where i have the list, add, modify and delete actions. With the twig render() function, I'm rendering the searchBar in the items list page. Which is the correct way to get the values from the 'key' and the 'term' elements and use them to make queries against the db?
I have tried to achieve this without the searchController/searchType and I used a simple <form> in the template and got the key and term values with $request->get() method in the listAction. After I created a switch-case statement to execute queries according to the key value. I could achieve what i wanted like this, but I want to be able to do this the correct way.
Can someone help me/give me some hints on how to continue from this?
Thanks.
Update:
Items Controller:
/**
*#Route("/items", name="items")
*/
public function listAction(Request $request){
$em = $this->getDoctrine()->getManager();
$items = $em->getRepository('AppBundle:Item')->findAll();
return $this->render('items.html.twig', ['items' => $items]);
}
My items.html.twig:
{% extends base.html.twig %}
{% block body %}
{{ render(controller('AppBundle:search:search')) }}
...
{% endblock %}
My searchBar.html.twig:
{{ form_start(form, {'attr': {'class': 'form-inline float-left my-2 my-lg-0'}}) }}
{{ form_widget(form.key) }}
{{ form_widget(form.term, {'attr': {'class': 'ml-1'}}) }}
{{ form_widget(form.buscar, {'attr': {'class': 'btn btn-outline-success ml-1'}}) }}
{{ form_end(form) }}
What i tried with routing and works with the searchController:
/**
* #Route("/search", name="search")
*/
public function searchAction(Request $request){
$em = $this->getDoctrine()->getManager();
$formulario = $this->createForm('AppBundle\Form\SearchType');
$formulario->handleRequest($request);
if($formulario->isSubmitted() && $formulario->isValid()){
$data = $formulario->getData();
$key = $data["key"];
$term = $data["term"];
$items = $em->getRepository('Item::class')->findByTerm($key, $term);
return $this->render('items.html.twig', ['items' => $items]);
}
return $this->render('searchBar.html.twig', ['form' => $formulario->createView()]);
}
If i go to /search and search for an item, it redirects me to my items page with the item i searched. But, If i use the search bar in my items page that i rendered using {{ render(controller('AppBundle:search:search')) }}, it doesn't work.
You are not very far from reaching your goal.
On your Controller, you can update your code to process the incoming request:
public function searchAction(Request $request){
$formulario = $this->createForm('AppBundle\Form\SearchType');
$formulario->handleRequest($request);
if ($formulario->isSubmitted() && $formulario->isValid()) {
$data = $formulario->getData();
// ... perform some action, such as saving the data to the database or search
}
return $this->render('searchBar.html.twig', ['form' => $formulario->createView()]);
}
You can find here more information about Processing Forms
To search into your database, you can process your repositories corresponding to the data. For more information about that, you can go here on Symfony Doctrine documentation
To go further, there is a bundle allowing simplified management of search forms: Lexik Form Filter Bundle
I have a question regarding showing data from my database in Laravel.
I get the following error:
Trying to get property 'first_name' of non-object
It refers to this line of code:
#foreach ($contact as $c)
<h1 class="display-4">Bekijk details voor contact: {{ $c->first_name }} {{ $c->last_name }}</h1>
#endforeach
I get this data from my database by using Laravel's 'show' function as described below:
public function show($id)
{
$contact = Contact::find($id);
return view('contacts.show', compact('contact'));
}
My routing looks like this:
Route::resource('contacts', 'ContactController');
The reason I can't get my head wrapped around this error is because it seems to work just fine for other functions like Laravel's 'edit' function as described below:
public function edit($id)
{
$contact = Contact::find($id);
return view('contacts.edit', compact('contact'));
}
Any help would be appreciated, I would like to know why it is not working for my 'show' function whilst it is working for my 'edit' function, are there any differences I am not aware of?
Thanks in advance!
Kind regards,
Geert-Jan Knapen
Very likely, $contact is the object rather than collection, so you do not need to loop through it. you can access it directly.
<h1 class="display-4">Bekijk details voor contact: {{ $contact ->first_name }} {{ $contact ->last_name }}</h1>
Update it's better to use route model binding, so it handles if the contact does not exist.
public function show(Contact $contact)
{
return view('contacts.show', compact('contact'));
}
I currently getting an error if I try to render a conditionally added form element in twig. The form element was added (or not) through the form event listener mechanism and should only add the form element if a specific form option is set.
Error
Argument 1 passed to Symfony\Component\Form\FormRenderer::searchAndRenderBlock() must be an instance of Symfony\Component\Form\FormView, null given
Form
<?php
namespace Vendor\ProjectBundle\Form\Type;
// [...]
abstract class AbstractContextualInfoFormType extends AbstractFormType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('user', new UserFormType($this->getTranslator(), $this->getDoctrine()), array('error_bubbling' => true, 'validation_groups' => 'ValidationGroup'));
$creditcardForm = new CreditcardFormType($this->getTranslator(), $this->getDoctrine());
$creditcardForm->setProcess($options['process']);
$creditcardForm->setProvider($options['provider']);
if (array_key_exists('cvc', $options)) {
$creditcardForm->setRequireCvc($options['cvc']);
}
if (array_key_exists('types', $options)) {
$creditcardForm->setAllowedCreditcardTypes($options['types']);
}
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($options) {
if (!array_key_exists('disable_creditcard', $options) OR (array_key_exists('disable_creditcard', $options) AND $options['disable_creditcard'] === true)) {
$creditcardForm = new CreditcardFormType($this->getTranslator(), $this->getDoctrine());
$creditcardForm->setProcess($options['process']);
$creditcardForm->setProvider($options['provider']);
if (array_key_exists('cvc', $options)) {
$creditcardForm->setRequireCvc($options['cvc']);
}
if (array_key_exists('types', $options)) {
$creditcardForm->setAllowedCreditcardTypes($options['types']);
}
$form = $event->getForm();
$form->add('creditcard', $creditcardForm, array('error_bubbling' => true));
}
}
);
}
}
// [...]
As you can see i try to add the credit card form only if the option disable_creditcard is not set. This all works fine until the moment I try to browse the page where I implemented the form:
Template
{% if not disable_creditcard %}
<div id="detail_creditcard" class="creditcard">
<legend>{{ 'creditcard.content.title'|trans }}</legend>
<div class="alert alert-info">
<i class="icon-info-sign"></i>
Bla bla bla text
</div>
**{{ form_row(form_data.creditcard.owner) }}**
{{ form_row(form_data.creditcard.number) }}
{{ form_row(form_data.creditcard.type) }}
{{ form_row(form_data.creditcard.validity) }}
{{ form_rest(form_data.creditcard) }}
</div>
{% endif %}
I also tried it with a surrounded conditional-if, but that doesn't work at all... I think twig needs the "not defined" creditcard form element here but cannot find it.
What is the right way for doing this? I would appreciate any help from you. :-)
Thanks!
try this:
{% if form_data.creditcard is defined %}
... your conditional code here
{% endif %}
I got a problem with a dynamic form on symfony2. I'm trying to generate some fields for a submitted form. In others words, the user enters some values, submits the form, and according to these values, my dynamics fields are added to this same form (which is, obviously, displayed a second time). To do that, I used this example from the cookbook : http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data
So, here is my FormationType class
class FormationType extends AbstractType
{
private $em;
private $context;
public function __construct($em, $context) {
$this->em = $em;
$this->context = $context;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('date')
->add('type', 'choice', array(
'mapped' => false,
'choices' => Formationlist::getTypeTypes(false),
'empty_value' => false,
))
->add('cost')
->add('travelCost')
->add('maximum')
->add('location')
->add('schedule')
;
$formModifier = function(FormInterface $form, $type) {
$formationList = $this->em->getRepository('CoreBundle:FormationList')->findBy(array("year" => 1, "type" => $type));
$form->add('formationList', 'entity', array(
'label'=> 'Titre formation',
'choices' => $formationList,
'class' => 'CoreBundle:FormationList',
'property' => 'title',)
);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function(FormEvent $event) use ($formModifier) {
$data = $event->getForm();
$type = $data->get('type')->getData();
$formModifier($event->getForm(), $type);
}
);
$builder->get('type')->addEventListener(
FormEvents::POST_SUBMIT,
function(FormEvent $event) use ($formModifier) {
$type = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $type);
}
);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'EXAMPLE\CoreBundle\Entity\Formation'
));
}
public function getName()
{
return 'example_corebundle_formationtype';
}
}
So, the two addEventListener work pretty well. The first time my form is displayed, the field in formModifier is not loaded, as expected. My controller class is the following one :
public function createAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$contextSrv = $this->get('example.service.context');
$context = $contextSrv->getContext();
$entity = new Formation();
$form = $this->createForm(new FormationType($em, $context), $entity);
$form->bind($request);
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('formation_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
Since one of my dynamic field can't be null, the first time the form is submitted, it can't be valid. So, the FormationType is loaded a second time. That means, if the field "type" was filled, my formModifier() function can load the dynamic field (formationList). Until there, everything works pretty well, and I got my new field.
But, after a second "submit" on the form...nothing happen. The page is just reloaded, and no errors are displayed.
I checked the form content with
var_dump($request->request->get('example_corebundle_formationtype'));
-> Every fields (including the dynamic one) are filled with valid values.
I also try this :
foreach($form->all() as $item) {
echo $item->getName();
var_dump($item->getErrors());
}
-> These lines don't show any error. But, the form is never valid.
var_dump($form->isValid());
-> It returns false. So the form is invalid.
Finally, if I remove the whole dynamic part, my form works.
I don't understand what's wrong. There is no errors displayed by the form, and the csrf token seems right. Did I miss something ? Thanks for your help.
I know this is a bit outdated but comes up quite high on Google.
The getErrors() metod returns only Form's global errors not error messages for the underlying fields, you need either getErrors(true) or more sophisticated method when using embeded forms in a form. Please see: https://knpuniversity.com/blog/symfony-debugging-form-errors for more information.
There is probably a validation error lying somewhere in your form.
Instead of your complicated calls to Form::getErrors() - which is not fully recursive, as the errors of any field deeper than the 2nd level will not be displayed - you should use Form::getErrorsAsString().
This is a debug method created by the Symfony guys for developers such as you, trying to understand where a validation error could lie in complex forms.
If no error is displayed although it should, this may be a form theming error. When creating a custom form theme, it is possible that a developper overrides or forgets to display the error block of a field.
Another possible source of the problem lies is the general display of the form. If you display your form using {{ form_widget(form) }}, then any error that bubbles to the top form will never be displayed. Make then sure that you use {{ form_row(form) }} instead.
I also encountered this problem a few times.
In my case I posted data in JSON format, so I had to do a request listener with a high priority which transforms json data into normal POST data, which is available in $request->request.
One scenario where the $form is invalid and there is no errors in also when the post data is empty, try to make a dump of $request->request->all() to see if you have the data.
I am using the same form to "preview" an object as I am to "edit/update" the same object.
In my showAction() for the controller I have the following code:
$form = $this->createForm(new SalesEntityType($entity), $entity, array('read_only' => true) );
This code works great for the primary form but there are a number of subforms that are made part of this by inclusion. One example in the show.html.twig is:
{% include 'TargetCommonBundle:Hours:hoursForm.html.twig' with { form: hours } %}
Unfortunately, the read_only setting on the parent form does not seem to cascade to the included subforms. Is there a way to handle this?
Try:
$form = $this->createForm(
new SalesEntityType($entity),
$entity,
[ 'disabled' => true ]
);
See: vendor/symfony/symfony/src/Symfony/Component/Form/CHANGELOG.md, first line
// It is the way more fast to disabled a form
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->setDisabled(true);
}