Validate and process form in different routes, Symfony2 - forms

I'm doing a search page for my users. Form is displayed in the path /home and the collected data is sent to the path /search. There these are used to do a search which I show at /search. The problem is that if the form is processed at /search and there is any validation error the form is reloaded in /search and not at /home. Is there any way to get this?
//routing.yml
home:
path: /
defaults: { _controller: UsuarioBundle:Default:home}
search:
path: /search
defaults: { _controller: UsuarioBundle:Default:search}
.
//UsuarioBundle/Controller/DefaultController.php
public function homeAction()
{
$request = $this->getRequest();
$usuario = new Usuario();
$formulario = $this->createForm(new UsuarioBusquedaType(), $usuario, array(
'action' => $this->generateUrl('search'),
'method' => 'POST',
));
return $this->render('UsuarioBundle:Default:portada.html.twig', array('formulario' => $formulario->createView() ));
}
public function searchAction()
{
$request = $this->getRequest();
$usuario = new Usuario();
$formulario = $this->createForm(new UsuarioBusquedaType(), $usuario, array(
'action' => $this->generateUrl('search'),
'method' => 'POST',
));
$formulario->handleRequest($request);
if ($formulario->isValid()) {
// Validate and search in DB
return $this->render('UsuarioBundle:Default:resultado.html.twig', array('usuarios' => $usuarios));
}
return $this->render('UsuarioBundle:Default:portada.html.twig', array('formulario' => $formulario->createView() ));
I have also tried to do so: display the form and process it in the same path /home and then send the data through a redirection but I don’t know how to pass data to the new route. Any idea?
Thanks in advance.

You could try something like this:
if ($formulario->isValid()) {
// Validate and search in DB
return $this->render('UsuarioBundle:Default:resultado.html.twig', array('usuarios' => $usuarios));
}
return $this->homeAction();

Related

How to make a Symfony GET form redirect to route with parameter?

I want to create a form for searching a profile by username which redirect then to the profile page of the user. Btw, I use Symfony 3.2.
I reckon the natural way for doing this would be a GET action form. It would even allow a customer to change the url directly with the good username to see its profile.
Here is the code of my controller :
ProfileController.php
//...
/** #Route("/profil/search", name="profil_search") */
public function searchAction() {
$builder = $this->createFormBuilder();
$builder
->setAction($this->generateUrl('profil_show'))
->setMethod('GET')
->add('username', SearchType::class, array('label' => 'Username : '))
->add('submit', SubmitType::class, array('label' => 'Search'));
$form = $builder->getForm();
return $this->render('profils/profil_search.html.twig', [
'form' => $form->createView(),
]);
}
/** #Route("/profil/show/{username}", name="profil_show") */
public function showAction($username) {
$repository = $this->getDoctrine()->getRepository('AppBundle:User');
$searchedUser = $repository->findOneByUsername($username);
return $this->render('profils/profil_show.html.twig', [
'searchedUser' => $searchedUser,
]);
}
//...
This code will lead to the following error message :
Some mandatory parameters are missing ("username") to generate a URL for
route "profil_show".
I read the documentation thoroughly but couldn't guess, how can I pass the username variable to the profil_show route as a parameter ?
If my way of doing is not the good one, thanks for telling me in comments but I'd still like to know how to use GET forms.
EDIT :
Thanks to #MEmerson answer, I get it now. So for future noobs like me, here is how I did it :
/** #Route("/profil/search", name="profil_search") */
public function searchAction(Request $request) {
$data = array();
$builder = $this->createFormBuilder($data);
$builder
//->setAction($this->generateUrl('profil_show'))
//->setMethod('GET')
->add('username', SearchType::class, array('label' => 'Username : '))
->add('submit', SubmitType::class, array('label' => 'Search'));
$form = $builder->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
return $this->redirectToRoute('profil_show', array('username' => $data["username"]));
}
return $this->render('profils/profil_search.html.twig', [
'method' => __METHOD__,
'form' => $form->createView(),
'message' => $message,
]);
}
If you take a look at the error message it says that the problem is where you are trying to generate the URL for the path 'profil_show'.
Your controller annotations require that the URL be populated with a user name
/** #Route("/profil/show/{username}", name="profil_show") */
this means that Symfony is expecting http://yoursite.com/profil/show/username for the route. But if you want to pass it as a GET form posting it really should be expecting http://yoursite.com/profil/show?username
you can add a second route or change your existing route to be
/** #Route("/profil/show", name="profil_show_search") */
that should solve your problem.

Validation error messages as JSON in Laravel 5.3 REST

My app is creating a new entry via a POST request in an api end point.
Now, if any validation is failed then instead of returning an error json, laravel 5.3 is redirecting the request to home page.
Here is my controller:
public function create( Request $request )
{
$organization = new Organization;
// Validate user input
$this->validate($request, [
'organizationName' => 'required',
'organizationType' => 'required',
'companyStreet' => 'required'
]);
// Add data
$organization->organizationName = $request->input('organizationName');
$organization->organizationType = $request->input('organizationType');
$organization->companyStreet = $request->input('companyStreet');
$organization->save();
return response()->json($organization);
}
If there is no issue with validation then the entity will be successfully added in the database, but if there is issue with validating the request then instead of sending all the error messages as a json response it redirects back to the home page.
How i can set the validate return type to json, so with every request if the validation failed then laravel will send all the error messages as json by default.
You can do your validation as:
$validator = \Validator::make($request->all(), [
'organizationName' => 'required',
'organizationType' => 'required',
'companyStreet' => 'required'
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422)
}
The validation used in the question looks as per the recommendation by laravel. The reason of redirection is that it throws an exception which you can easily catch using the code below. So it's better to use the recommended way of code instead of re-writing framework's code again :)
public function create( Request $request )
{
$organization = new Organization;
// Validate user input
try {
$this->validate($request, [
'organizationName' => 'required',
'organizationType' => 'required',
'companyStreet' => 'required'
]);
} catch (ValidationException $e) {
return response()->json($e->validator->errors(), 422);
}
// Add data
$organization->organizationName = $request->input('organizationName');
$organization->organizationType = $request->input('organizationType');
$organization->companyStreet = $request->input('companyStreet');
$organization->save();
return response()->json($organization, 201);
}

Silex default_target_path not working after successful login

I've got a problem ith redirect after successful login.
App.php file (part of it):
<?php
use Silex\Application;
/** ... */
use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder;
$app = new Application();
/** ... */
$app['security.encoder.digest'] = $app->share(function ($app) {
return new PlaintextPasswordEncoder();
});
$app['security.firewalls'] = array(
'secured' => array(
'pattern' => '^/admin/',
'form' => array(
'login_path' => '/login',
'check_path' => '/admin/login_check',
'default_target_path' => '/admin/news',
'always_use_default_target_path' => true,
),
'logout' => array(
'logout_path' => '/admin/logout',
),
'users' => array(
'admin' => array('ROLE_ADMIN', 'test'),
),
),
);
My controllers.php file:
<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$app->get('/login', function(Request $request) use ($app) {
return $app['twig']->render('login.html.twig', array(
'error' => $app['security.last_error']($request),
'last_username' => $app['session']->get('_security.last_username'),
));
});
$app->get('/admin/news', function(Request $request) use ($app) {
if ($app['security.authorization_checker']->isGranted('ROLE_ADMIN')) {
echo 'admin';
}
});
I am logged in (after passing correct login data in form), I have access to /admin/news route, but I have to go to that address manually. I'd like to be redirected there automatically after successful login. Now I'm kept in /login page. When I change default_target_path to 'http://google.com', it works properly.
I use homestead (vagrant) with nginx. Silex 1.3.0.
I'll appreciate any help.
The solution (or rather workaround) which worked was:
change 'default_target_path' to '/admin';
add new route:
$app->get('/admin', function() use ($app) {
return $app['twig']->render('admin/loggedIn.html.twig');
});
in admin/loggedIn.html.twig template I've added js redirect to admin/news
I don't have any idea why wasn't it working. If anyone knows - please leave a comment.

Symfony2 autocomplete form bundle

I use this bundle: GenemuFormBundle
I install it due to all information on this site.
But it still dont work.
Here is my type form:
$builder
->add('PermitsCompany', 'genemu_jqueryautocompleter_entity', array(
'route_name' => 'ajax_company',
'class' => 'MainCoreBundle:Company',
'property'=>'name'
))
;
Here is my routing:
ajax_company:
defaults: { _controller: MainAdminBundle:Permits:ajaxCompany}
pattern: /ajax_company/
type: annotation
And here is my controller:
/**
* #Route("/ajax_company", name="ajax_company")
*/
public function ajaxCompanyAction(Request $request)
{
$permits = $this->getDoctrine()->getRepository('MainCoreBundle:Company')->findAll();
$json = array();
foreach ($permits as $permit) {
$json[] = array(
'label' => $permit->getName(),
'value' => $permit->getId()
);
}
$response = new Response(json_encode($json));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
I have no idea what I am doing wrong. I have no error. But autocomplete did not work.
When i go to route /ajax_company/ i can see values from data base like here:
[{"property":"Company 1","value":1},{"property":"Company 2","value":2},{"Company":"Company 3","value":3},{"property":"Company 4","value":4}]
Did I add forget something in twig? I have only form_widget
Try including form_javascript or form_stylesheet, in your twig template.
From https://github.com/genemu/GenemuFormBundle#template:
Template
You use GenemuFormBundle and you seen that it does not work! Maybe you
have forgotten form_javascript or form_stylesheet.
The principle is to separate the javascript, stylesheet and html. This
allows better integration of web pages.

Load Form from module into custom page template

I have successfully added my own form (from the same module) into my custom template, but now I wish to load the taxonomy add term form (used by ubercart I think for product categories in the catalog vocab) into my template.
I have gotten this far with my module - filename simpleadmin.module
/**
* #file
* A module to simplify the admin by replacing add/edit node pages
*/
function simpleadmin_menu() {
$items['admin/products/categories/add'] = array(
'title' => 'Add Category',
'page callback' => 'simpleadmin_category_add',
'access arguments' => array('access administration pages'),
'menu_name' => 'menu-store',
);
return $items;
}
function simpleadmin_category_add() {
module_load_include('inc', 'taxonomy', 'taxonomy.admin');
$output = drupal_get_form('taxonomy_form_term');
return theme('simpleadmin_category_add', array('categoryform' => $output));
}
function simpleadmin_theme() {
return array(
'simpleadmin_category_add' => array(
'template' => 'simpleadmin-template',
'variables' => array('categoryform' => NULL),
'render element' => 'form',
),
);
}
?>
And as for the theme file itself - filename simpleadmin-template.tpl.php, only very simple at the moment until I get the form to load into it:
<div>
This is the form template ABOVE the form
</div>
<?php
dpm($categoryform);
print drupal_render($categoryform);
?>
<div>
This is the form template BELOW the form
</div>
Its telling me that it is
Trying to get property of non-object in taxonomy_form_term()
and throwing up an error. Should I be using node_add() and passing the nodetype?
To render a taxonomy term form, the function should be able to know the vocabulary to which it belongs to. Otherwise how would it know which form to show? I think this is the proper way to do it.
module_load_include('inc', 'taxonomy', 'taxonomy.admin');
if ($vocabulary = taxonomy_vocabulary_machine_name_load('vocabulary_name')) {
$form = drupal_get_form('taxonomy_form_term', $vocabulary);
return theme('simpleadmin_category_add', array('categoryform' => $form));
}
To redirect your form use hook_form_alter
function yourmodule_form_alter(&$form, &$form_state, $form_id) {
//get your vocabulary id or use print_r or dpm for proper validation
if($form_id == 'taxonomy_form_term' && $form['#vocabulary']['vid'] = '7' ){
$form['#submit'][] = 'onix_sections_form_submit';
}
}
function yourmodule_form_submit($form, &$form_state) {
$form_state['redirect'] = 'user';
}