HTTP Routing in Symfony - php

I've been developing a lot of my projects in the Laravel Framework for quite a while now, but not I'm working for a company who uses Symfony instead of Laravel.
On my way adapting to Symfony I got confused with the HTTP routing.
In Laravel you specify the HTTP method and link it to a route, like so:
Route::get('/', 'PageController#index');
Route::post('/', 'PageController#contact');
If you send a get request to '/' it will call the index method in PageController. If you send a post request it will call the contact method in PageController.
Now in Symfony I don't know how to do proper HTTP routing. I've seen people handle both get and post request in one method. For example:
public function index()
{
if ($request->isMethod('POST')) {
// handle post request and return something
}
// return something else
}
What I did, which looks a lot like the Laravel way is specifying 2 separate methods to handle each request:
/**
* #Route("/", name="homepage")
* #Method("GET")
*/
public function indexAction(Request $request)
{
// return the index page
}
/**
* #Route("/", name="contact")
* #Method("POST")
*/
public function contactAction()
{
// handle post request and return something
}
To summarize my question(s):
How to handle post requests in Symfony?
What are the best-practises to handle those requests?
What are naming conventions for such methods (indexPost/indexGet, indexAction/contactAction)?
Thanks in advance!

I'll try to go through each of your questions,
How to handle post requests in Symfony
Example with YML routes
my_route_post:
path: /route/path
defaults: { _controller: AppBundle:Foo:edit }
methods: [POST]
my_route_get:
path: /route/path
defaults: { _controller: AppBundle:Foo:show }
methods: [GET]
And you can define the controller actions :
class FooController extends Controller {
public function editAction(Request $request)
{
// POST request here
}
public function showAction()
{
// GET request here
}
}
What are the best-practises to handle those requests
I think both practises of creating a controller action to handle each HTTP request types or handling a POST request in the same method as GET are fine. Depending on which one fits your needs the best.
What are naming conventions for such methods (indexPost/indexGet, indexAction/contactAction)?
Each action method in a controller class is suffixed with Action
(again, this isn't required, but some shortcuts rely on this).
From : https://symfony.com/doc/current/controller.html

Related

Prestashop get static token for controler

I am developing a module that has function that need to run periodically in cron.
The idea of implementation is to create a controller that third party cron module is going to call. My problem is that in order to call that controller a token is needed. Tokens in admin panel are temporary per session. Is there any way to get static token for a certain controller? Or is there a better way to implement what I want (through api or something)?
routes.yml:
admin_mymodule_myaction:
path: /mymodule/myaction
methods: [GET]
defaults:
_controller: 'PrestaShop\Module\MyModule\Controller\Admin\MyController::myAction'
MyController.php:
class MyController extends FrameworkBundleAdminController{
public function myAction(){
...
}
}
link to controller (token is temporary):
http://localhost/admin303/index.php/modules/mymodule/myaction?_token=uPmkkqeqBVfnjUGdLKs9_Ik585Q1GlsXWK-qiGfC3r0
I found the solution.
I need to use Front controller, NOT Admin controller. Front controller needs no token, I can define my own security system.
https://devdocs.prestashop.com/1.7/modules/concepts/controllers/front-controllers/#using-a-front-controller-as-a-cron-task
mymodule/controllers/front/cron.php:
<?php
class MyModuleCronModuleFrontController extends ModuleFrontController
{
/** #var bool If set to true, will be redirected to authentication page */
public $auth = false;
/** #var bool */
public $ajax;
public function display()
{
$this->ajax = 1;
//my functionality goes here
$this->ajaxDie("OK.");
}
}
and the link to trigger functionality will be:
http://localhost/index.php?fc=module&module=mymodule&controller=cron
Wonder why official documentation did not come up during Google search.

How to route to two different 'Action' functions in same controller using annotation - Symfony2

Recently I shifted from Symfony 2.4 to Symfony 2.7
So I was following the new docs. Now say I have 2 action functions in same controller.
public function indexAction() {}
public function changeRateAction()
Previously I would have route them using routing.yml
change_interest_rate_label:
path: /change_interest_rate
defaults: { _controller: appBundle:appInterestRateChange:index }
change_interest_rate_action_label:
path: /change_interest_rate_and_archived_action
defaults: { _controller: appBundle:appInterestRateChange:changeRate }
Now in 2.7 docs, annotations are encourages. Inside controller file
/**
* #Route("/home", name="homepage")
*/
This will fire the action method contains in the controller file. But how can I write annotations for 2 methods for different urls included in the same controller file ?
That means I have indexAction & changeRateAction in same controller file. I want to route url /home with index function and /change with changeRate function. How to do this using annotations ? I know how to do this using routing.yml
You use the annotation routing on a method, not a controller, really.
You just specify the route before every method. In your case it would be something like this:
/**
* #Route("/home", name="homepage")
*/
public function indexAction() {
...
}
/**
* #Route("/change", name="changerate")
*/
public function changeRateAction() {
...
}
Be sure to read more about routing in the documentation: http://symfony.com/doc/current/book/routing.html

Laravel 5, how to run a specific method according to the URL received

In my routes files I have a bunch or routes for testing purposes:
/** testing controllers */
Route::get('viewemail', 'TestController#viewemail');
Route::get('restore', 'TestController#restore');
Route::get('sendemail', 'TestController#send_email');
Route::get('socket', 'TestController#socket');
Route::get('colors', 'TestController#colors');
Route::get('view', 'TestController#view_test');
Route::get('numbers', 'TestController#numbers');
Route::get('ncf', 'TestController#ncf');
Route::get('dates', 'TestController#dates');
Route::get('print', 'TestController#printer');
Route::get('{variable}', 'TestController#execute');
/** End of testing controllers */
I want to eliminate all those routes and simple use the name of the given URL to call and return the method:
I have accomplished that in this way:
Route::get('{variable}', 'TestController#execute');
And in my testing controller:
public function execute($method){
return $this->$method();
}
Basically what I want to know if Laravel has a built in solution to do this, I was reading the documentation but couldn't find any way to accomplish this.
From official documentation:
http://laravel.com/docs/5.1/controllers#implicit-controllers
Laravel allows you to easily define a single route to handle every
action in a controller class. First, define the route using the
Route::controller method. The controller method accepts two
arguments. The first is the base URI the controller handles, while the
second is the class name of the controller:
Route::controller('users', 'UserController');
Next, just add methods to your controller. The method names should begin with the
HTTP verb they respond to followed by the title case version of the
URI:
<?php
namespace App\Http\Controllers;
class UserController extends Controller
{
/**
* Responds to requests to GET /users
*/
public function getIndex()
{
//
}
/**
* Responds to requests to GET /users/show/1
*/
public function getShow($id)
{
//
}
/**
* Responds to requests to GET /users/admin-profile
*/
public function getAdminProfile()
{
//
}
/**
* Responds to requests to POST /users/profile
*/
public function postProfile()
{
//
}
}
As you can see in the example above, index methods will respond to the
root URI handled by the controller, which, in this case, is users.
You could add a route pattern for the endpoints you want to listen for. Route them to a controller action, and then inspect the request:
class TestController extends Controller
{
public function handle(Request $request)
{
$method = $request->segment(1); // Gets first segment of URI
// Do something…
}
}
And in your route service provider:
$router->pattern('{variable}', 'foo|bar|qux|baz');

Symfony: Two actions one route

I have controller where I have two actions: createAction and showAction.
createAction creates form from form class and renders it to index.html.twig.
showAction makes database query and takes there some data and renders it to index.html.twig (same .twig file as before).
How I can have two actions in one route? I tried to do two same routes but different name in routing.yml, but it doesn't work. It only renders the first one.
(Sorry, bad english)
You can have the same URL for two separate actions as long as they respond to different http verbs (POST/GET/PUT/etc). Otherwise how would you expect the router to decide which action to choose?
Learn how to define http method requirements from the Adding HTTP Method Requirements section of the Routing documentation.
An example of annotation configuration:
class GuestbookController
{
/**
* #Route("/guestbook")
* #Method("POST")
*/
public function createAction()
{
}
/**
* #Route("/guestbook")
* #Method("GET")
*/
public function showAction()
{
}
}

Defining a route in Symfony 2 with variable action

Just imagine, I have a controller with several actions in it.
And to reach each action I have to define it strictly in routing.yml file like this:
admin_edit_routes:
pattern: /administrator/edituser
defaults: { _controller: MyAdminBundle:Default:edituser }
admin_add_routes:
pattern: /administrator/adduser
defaults: { _controller: MyAdminBundle:Default:adduser }
And I can have plenty of such pages. What I want to achieve is to define necessary action in my URI, just like Kohana routes do.
I mean, I want simply to use one route for all actions:
(code below is not valid, just for example)
admin_main_route:
pattern: /administrator/{action}
defaults: { _controller: MyAdminBundle:Default:{action} action:index}
It will pass all requests to /administrator/{anything} to this route, and after that, according to the action, stated in the uri, the needed action is gonna to be called.
If action is not stated in the uri, then we got thrown to index action.
Is it possible in Symfony 2 in any ways and if yes, then how?
Thanking in advance.
This doesn't feel right to do so. By exposing your controller API (methods) "on the fly" directly via GET method, you open your application to security vulnerabilities. This can also easily lead to unwanted behaviours.
Moreover, how would you generate routes in twig for example ? By giving explicit constants tied to the method names?
{{ path('dynamic_route', { 'method': 'addUser' }) }}
This is not how Symfony works nor what it recommands. Symfony is not CodeIgniter nor Kohana. You don't need a second "Front Controller"
If this is a laziness matter, you can switch your routing configurations to annotations. And let Symfony auto-generate the routes you need, with minimal efforts.
namespace Acme\FooBundle\Controller;
/**
* #Route("/administrator")
*/
class DefaultController extends Controller
{
/**
* #Route
*/
public function indexAction(Request $request);
/**
* #Route("/adduser")
*/
public function addUserAction(Request $request);
/**
* #Route("/edituser")
*/
public function editUserAction(Request $request);
/**
* #Route("/{tried}")
*/
public function fallbackAction($tried, Request $request)
{
return $this->indexAction($request);
}
}
The fallbackAction methods, returns any /administrator/* route which does not exist to the indexAction content.
To sum up, I advise not to use dynamic routing "on the fly" directly to method names.
An alternative would be to create a command which will generate routes once executed.
Well, maybe that's not the best way to do that, but it works. Your dynamicAction accepts action string parameter and checks if such action exists. If so, it executes given action with params.
/**
* Default Controller.
*
* #Route("/default")
*/
class DefaultController extends Controller
{
/**
* #Route("/{action}/{params}", name="default_dynamic")
*/
public function dynamicAction($action, $params = null)
{
$action = $action . 'Action';
if (method_exists($this, $action)) {
return $this->{$action}($params);
}
return $this->indexAction();
}
}
I'm curious if someone have any other ideas :>

Categories