Laravel 4 change form open with if else statement - forms

I'm new to Laravel and trying some stuff out. Hope you guys can point me in the right direction.
I have a form to add categories on a the page with the overview of all the categories. Now I'm routing to the same page when you want to add or edit a category. Problem is, I want the normal add form to show when the url is category/add and when the url is category/edit/id I want it to show the form to edit (with form model binding). I placed the code in an if else statement, but it always shows the edit form, therefore if I want to add a new category on the url categories I get an error because it's the edit form.
Here's the code in the index.bade.php:
#if(Request::url() === 'categories' )
{{ Form::open(array('url' => 'category/add', 'class' => 'form-horizontal')) }}
#else
{{ Form::model($category, array(
'url' => 'category/edit/'.$category->id ,
$category->id,
'class' => 'form-horizontal'))
}}
#endif
My controller:
public function index()
{
$categories = Category::get();
$category = new Category();
View::share('title', 'Mini Blog - Categories');
$view = View::make('category.index')->with('category', $category);
$view->categories = $categories;
return $view;
}
public function edit($id)
{
$categories = Category::get();
$category = Category::find($id);
View::share('title', 'Mini Blog - Edit category');
return View::make('category.index')->with(array('category' => $category, 'categories' => $categories));
}
Is this the way to go? Or is there a better way?

Instead of checking the URL I suggest you depend on the model variable. Ever Eloquent model has a property exists that tells you if the model has been loaded from the DB or it's a new instance.
#if( ! $category->exists)
{{ Form::open(array('url' => 'category/add', 'class' => 'form-horizontal')) }}
#else
{{ Form::model($category, array(
'url' => 'category/edit/'.$category->id ,
$category->id,
'class' => 'form-horizontal'))
}}
#endif
Actually you can use Form::model with an empty model as well, so you should be able to reduce it to this:
{{ Form::model($category, array(
'url' => ($category->exists ? 'category/edit/'.$category->id : 'category/add'),
'class' => 'form-horizontal'))
}}

There is a much better way.
In your controller do this:
public function create()
{
return View::make('create');
}
public function edit($id)
{
return View::make('edit')->withId($id);
}
Then in your views you have
Create.blade.php
{{ Form::open(array('url' => 'category/add', 'class' => 'form-horizontal')) }}
#include ('form')
{{ Form::close() }}
Edit.blade.php
{{ Form::model($category, array('url' => 'category/edit/'.$category->id, category->id, 'class' => 'form-horizontal')) }}
#include ('form')
{{ Form::close() }}
Form.blade.php
//Put your HTML form stuff here

Related

Drupal 9 - form in custom module using Controller - html tag form not present

I'm trying to render limited user edit form on custom page using Drupal Controller.
In the routing.yml I defined _controller, I do not want to use _form.
I want to display on the form e.g. only timezone field, but not the rest. And I'm not able to achieve it. I can render this field, other fields like form_build_id, form_id, form_token
But form html tag is not rendered at all.
It works only if I display in twig whole form like this {{ form.form }}
Here are my files:
my_module.info.yml
name: 'My module'
type: module
description: 'my module'
core_version_requirement: ^8.8 || ^9
my_module.routing.yml
my_module.mymodule_controller_view::
path: '/my-module'
defaults:
_controller: '\Drupal\my_module\Controller\MymoduleController::view'
_title: 'My module'
requirements:
_permission: 'access content'
my_module.module
<?php
function my_module_theme($existing, $type, $theme, $path)
{
$templates = array(
'my_module_form' => [
'render element' => 'form',
],
);
return $templates;
}
MymoduleController.php
<?php
namespace Drupal\my_module\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\user\Entity\User;
class MymoduleController extends ControllerBase
{
public function view()
{
$data['header'] = [
'#type' => 'markup',
'#markup' => '<h1>HEADER</h1>',
];
$user = User::load(\Drupal::currentUser()->id());
$formObject = \Drupal::entityTypeManager()
->getFormObject('user', 'default')
->setEntity($user);
$form = \Drupal::formBuilder()->getForm($formObject);
$data['form'] = [
'#theme' => 'my_module_form',
'form' => $form,
];
$data['footer'] = [
'#type' => 'markup',
'#markup' => '<h3>footer</h3>',
];
return $data;
}
}
my-module-form.html.twig
<div>TWIG TEMPLATE</div>
{{ form.form.timezone }}
{{ form.form.form_build_id }}
{{ form.form.form_token }}
{{ form.form.form_id }}
{{ form.form.actions }}
Thank you in advance for any hint.

How to integrate more than one form in one controller -> error at submit - Symfony 4.*

I'd like to know how can I put more than one form in one controller?
I did this, see the code below, in my controller which contains 2 forms; 1 to add a horse, and one to add a group of horses:
/*Add a horse*/
$cheval = new Chevaux();
$cheval->setParticulier($user->getParticulier());
$formAddHorse = $this->createFormBuilder($cheval)
->add('nom_cheval', TextType::class)
->add('save', SubmitType::class, array('label' => 'Ajouter'))
->getForm();
$formAddHorse->handleRequest($request);
if ($formAddHorse->isSubmitted() && $formAddHorse->isValid()) {
$cheval = $formAddHorse->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($cheval);
$em->flush();
return $this->redirectToRoute('app_acc');
}
/*add a group of horses*/
$team=new Team();
$team->setUser($user->getParticulier());
$formAddTeam = $this->createFormBuilder($team)
->add('profession', EntityType::class, array(
'class' => Profession::class,
'choice_label' => 'nom_prof',
'expanded' => true))
->add('save', SubmitType::class, array('label' => 'Nouvelle Team'))
->getForm();
$formAddTeam->handleRequest($request);
if ($formAddTeam->isSubmitted() && $formAddTeam->isValid()) {
$team = $formAddTeam->getData();
$em = $this->getDoctrine()->getManager();
/*
* Traitement des données
*/
return $this->redirectToRoute('app_acc');
}
and in the template :
<h2> -------Add a horse------ </h2>
{{ form_start(formHorse) }}
{{ form_widget(formHorse) }}
{{ form_end(formHorse) }}
<h2> ------------------------------ </h2>
<h2> -------Add team------ </h2>
{{ form_start(formTeam) }}
{{ form_widget(formTeam) }}
{{ form_end(formTeam) }}
<h2> ------------------------------ </h2>
However when I submit one of the forms, it seems that both are send. So it throws the error:
This form should not contain extra fields
in the form I didn't submit.
The data are send in the database properly, but the error is here and tells me that I am doing something wrong. How do I do to do this the right way?
I had a case like that once, here is what I did:
$form = $this->createForm(ProfileForm::class, $user);
$formPassword = $this->createForm(ChangePasswordForm::class, $user);
$form->handleRequest($request);
$formPassword->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
// My code to save some things...
}
}
if ($formPassword->isSubmitted()) {
if ($formPassword->isValid()) {
// My code to save some things...
}
}
It works for me but It seems like what you did, at first sight, though.
Maybe it's how you handle it in your template ?
You are looking for allow_extra_fields option which can be used like so.
$formBuilder = $this->createFormBuilder($team, array('allow_extra_fields' =>true))...
or like so for FormType class
public function setDefaultOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'allow_extra_fields' => true
)
);
}
This option allows you to submit some extra data, not specified in a form builder. As official documentation says
Usually, if you submit extra fields that aren't configured in your
form, you'll get a "This form should not contain extra fields."
validation error.
You can silence this validation error by enabling the
allow_extra_fields option on the form.

Sf2 split one formType in many form on one page

Here is what i would like to achieve. (i thought it would be easier).
I have a UserEntity.
Each field of this entity have an :
"#Assert\NotNull( groups={"step-1"} )"
or
"#Assert\NotNull( groups={"step-2"} )"
/** #ORM\Column(name="username", type="string", length=255, nullable = true)
* #Assert\NotNull(groups={"step-1"})
*/
protected $username;
/** #ORM\Column(name="city", type="string", length=255, nullable = true)
* #Assert\NotNull( groups={"step-2"} )
*/
protected $city;
On the formType, i have my 2 fields plus 2 submit buttons :
->add('username')
->add('city')
->add('submit_form_1', SubmitType::class, array(
'validation_groups' => 'step-1',
)
)
->add('submit_form_2', SubmitType::class, array(
'validation_groups' => 'step-2',
)
)
What i would like to do is display the Username inputType,followed by the submitOne button.
Then display the City inputType, followed by the submitTwo button.
Then , when the user click on submit One, validate the datas, and save persist this field in the database.
Here is my view :
{{ form_start(form, { 'action': path('fos_user_profile_edit'), 'attr': { 'novalidate' : 'novalidate', 'class': 'fos_user_profile_edit' } }) }}
{{ form_row(form.userType.city) }}
{{ form_widget(form._token) }}
{{ form_widget(form.userType.submit_form_2) }}
{{ form_end(form, {'render_rest': false}) }}
{{ form_start(form, { 'action': path('fos_user_profile_edit'), 'attr': { 'novalidate' : 'novalidate', 'class': 'fos_user_profile_edit' } }) }}
{{ form_row(form.userType.username) }}
{{ form_widget(form._token) }}
{{ form_widget(form.userType.submit_form_1) }}
{{ form_end(form, {'render_rest': false}) }}
When i submit the first form everything works great.
When i submit the second one, i've got a "Invalid CSRF token error" and indeed if i look at the dom, only the first form have an input type hidden with the CSRF token.
I did try to input manually the CSRF token (just as a test), and when i submit a form, the datas of this form are persisted, but the the data form the other form are set to null.
I'm kind of stuck right now.
Maybe i'm doing this wrong, the general idea is to split a single entity into differents forms on a same page.
Thanks !
I don't believe Symfony will let you render the CSRF token twice on one page for the same form because it will create security vulnerabilities. I believe the best approach here would be to create 2 separate forms that both use the same model. You can remove the groups and leave the constraints on the model or move them to the formType as well.
UsernameType.php
$builder
->add('username')
->add('submit',
SubmitType::class,
array(
'constraints' => array(
new NotNull()
)
)
)
;
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults(array(
'data_class' => userType::class
))
;
}
CityType.php
$builder
->add('city')
->add('submit',
SubmitType::class,
array(
'constraints' => array(
new NotNull()
)
)
)
;
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults(array(
'data_class' => userType::class
))
;
}
Controller:
$usernameType = new UsernameType();
$cityType = new CityType();
return array(
'usernameType' => $usernameType->createView(),
'cityType' => $cityType->createView()
);
Template:
{{ form(usernameType) }}
{{ form(cityType) }}

Submit Multiple Select Values to an Action in Laravel 4

I've been trying to figure out how to submit multiple multi-select values using a redirect or something similar to an index() method/action in my resource controller in Laravel 4.
I've made several attempts to achieve this but have yet to work out how to do it.
I initially had it submitting to a query string, which worked to a certain extent but as soon as you selected more than 1 value in a single multi-select box, it wouldn't work, as it simply chose to use the last value.
This is the form in my view, with several multi-select boxes. http://paste.laravel.com/s1n
At the moment it's posting to an action/method in my EventsController called postSearch(). http://paste.laravel.com/s1p This method then redirects to my index() method and is supposed to take with it a $search_data variable to then be used for selecting results from an Eloquent model using http://paste.laravel.com/s1q
Now these methos are a bit of a mess at the moment, as I have been trying several things to get this working,
If anyone can offer any guidance on this I would really appreciate it. Thanks.
OK, so I've figured out how to do this. It may not be the best or most elegant solution but it works and I can refactor it later on.
First in my view, is the form.
{{ Form::open(array('action' => 'EventsController#postSearch', 'method' => 'POST', 'class' => 'view-only pull-left form-inline')) }}
{{ Form::label('courses', 'Course', array('class' => 'label')) }}
{{ Form::select('courses[]', $courses, '', array('class' => 'input-medium field', 'multiple' => 'multiple')) }}
{{ Form::label('suppliers', 'Supplier', array('class' => 'label')) }}
{{ Form::select('suppliers[]', $suppliers, '', array('class' => 'input-medium field', 'multiple' => 'multiple')) }}
{{ Form::label('locations', 'Location', array('class' => 'label')) }}
{{ Form::select('locations[]', $locations, '', array('class' => 'input-medium field', 'multiple' => 'multiple')) }}
{{ Form::label('venues', 'Venue', array('class' => 'label')) }}
{{ Form::select('venues[]', $venues, '', array('class' => 'input-medium field', 'multiple' => 'multiple')) }}
{{ Form::label('event_statuses', 'Status', array('class' => 'label')) }}
{{ Form::select('event_statuses[]', $event_statuses, '', array('class' => 'input-medium field', 'multiple' => 'multiple')) }}
{{ Form::submit('Search', array('class' => 'btn btn-success')) }}
{{ Form::close() }}
And my refined postSearch method in my EventsController:
public static function postSearch()
{
$courses_value = Input::get('courses');
$suppliers_value = Input::get('suppliers');
$locations_value = Input::get('locations');
$venues_value = Input::get('venues');
$status_value = Input::get('event_statuses');
// $tutor_value = Input::get('tutors');
$search_data = array(
'courses_value' => $courses_value,
'suppliers_value' => $suppliers_value,
'locations_value' => $locations_value,
'venues_value' => $venues_value,
'status_value' => $status_value,
// 'tutor_value' => $tutor_value
);
return Redirect::to('events')->with($search_data);
}
Then my index method contains the following:
$courses_value = Session::get('courses_value');
$suppliers_value = Session::get('suppliers_value');
$locations_value = Session::get('locations_value');
$venues_value = Session::get('venues_value');
$status_value = Session::get('status_value');
// $tutor_value = Session::get('tutor_value');
if (is_null($courses_value)) {
$courses = Course::all();
$course_titles = array();
foreach ($courses as $course) {
$course_titles[] = $course->title;
}
$courses_value = $course_titles;
}
if (is_null($suppliers_value)) {
$suppliers = Supplier::all();
$supplier_names = array();
foreach ($suppliers as $supplier) {
$supplier_names[] = $supplier->name;
}
$suppliers_value = $supplier_names;
}
if (is_null($locations_value)) {
$locations = Location::all();
$location_cities = array();
foreach ($locations as $location) {
$location_cities[] = $location->city;
}
$locations_value = $location_cities;
}
if (is_null($venues_value)) {
$venues = Venue::all();
$venue_names = array();
foreach ($venues as $venue) {
$venue_names[] = $venue->name;
}
$venues_value = $venue_names;
}
if (is_null($status_value)) {
$event_statuses = EventStatus::all();
$statuses = array();
foreach ($event_statuses as $event_status) {
$statuses[] = $event_status->status;
}
$status_value = $statuses;
}
This is the bit that could probably do with refactoring. Anyway, now when I select my results using:
$events = Event::where('active', '=', 1)
->leftJoin('courses', 'courses.id', '=', 'events.course_id')
->leftJoin('suppliers', 'suppliers.id', '=', 'events.supplier_id')
->leftJoin('locations', 'locations.id', '=', 'events.location_id')
->leftJoin('venues', 'venues.id', '=', 'events.venue_id')
->leftJoin('event_types', 'event_types.id', '=', 'events.event_type_id')
->leftJoin('event_statuses', 'event_statuses.id', '=', 'events.event_status_id')
->leftJoin('tutors', 'tutors.id', '=', 'events.tutor_id')
->orderBy($order[0], $order[1])
->select(array('events.*', DB::raw('events.id as eid'), DB::raw('suppliers.name as sname'), DB::raw('locations.city as lcity'), DB::raw('venues.name as vname'), DB::raw('venues.city as vcity'), DB::raw('tutors.first_name as tfirst_name')))
->whereIn('courses.title', $courses_value)
->whereIn('suppliers.name', $suppliers_value)
->whereIn('locations.city', $locations_value)
->whereIn('venues.name', $venues_value)
->whereIn('event_statuses.status', $status_value)
// ->whereIn('tutors.first_name', $tutor_value)
->paginate($perPage);
I am now able to select single or multiple values in the multi-select boxes and the results show as expected, which is great.
There's probably a much better way of doing this, so if you guys know of one please let me know.
What would be nice is to store the submission data in a variable that is not retrieved from the session, so I can use pagination on the results and the user doesn't have to re-search if they refresh or move away from and back to the page.

symfony2: null date rendering

everyone
I’am having trouble with empty dates and forms in Symfony2.
When I create an entity with an empty date, it works fine, a NULL value is inserted in the database. But when I want to edit it, it renders as today, I found no way of rendering the empy_values
As expected, “preferred_choices” does not work because “date” is not a “choice”.
Seems that a new \DateTime() is called somewhere.
Index and show actions have no problem:
[index/show.html.twig]
{% if entity.dueDate %}
{{ entity.dueDate|date('Y-m-d') }}
{% endif %}
If I ask in the controller, the behaviour is the expected one
[controller]
if (!$entity->getDueDate()) {
// enters here when there is NULL in the database
}
Here is the entity and form definitions:
[entity]
/**
* #var date $dueDate
*
* #ORM\Column(name="dueDate", type="date", nullable="true")
*/
private $dueDate;
[form]
$builder->add('dueDate', 'date', array('label'=>'Due date', 'empty_value' => array('year' => '----', 'month' => '----', 'day' => '----'),'required'=>false))
Please give me a hint, thank you in advance.
There is a related question from 2011-06-26 with no answer in google groups
https://groups.google.com/forum/#!msg/symfony2/nLUmjKzMRVk/9NlOB1Xl5RwJ
http://groups.google.com/group/symfony2/browse_thread/thread/9cb5268caccc4559/1ce5e555074ed9f4?lnk=gst&q=empty+date+#1ce5e555074ed9f4
With modern version of Symfony you seem to need:
$builder->add('dueDate', DateType::class, array(
'placeholder' => ['year' => '--', 'month' => '--', 'day' => '--']
)
empty_value has been replaced by placeholder and you need to pass an array with each "empty" value.
You can solve this way:
$builder->add('dueDate', 'date', array(
'label'=>'Due date',
'empty_value' => array('----'),
'required'=>false
))
You were close to the solution.
I did not want to render the form by myself, but as I was already doing that due to an unrelated issue, I developed some kind of fix:
[edit.html.twig]
<div class="entry {% if not entity.dueDate %}nullabledate{% endif %}">
{{ form_label(form.dueDate) }}
{{ form_errors(form.dueDate) }}
{{ form_widget(form.dueDate) }}
</div>
[add to some javascript file]
jQuery(document).ready(function() {
var nullDate = function(id) {
$(".nullabledate select").each(function(key,elem){
$(elem).val('');
})
}
nullDate();
}