Redirecting in symfony - symfony

I'm trying to understand if there is any difference between these two ways to do a redirection in symfony.
1 Via config without custom controller
As explained here.
# app/config/routing.yml
# ...
codes:
path: /codes # redirect /codes to /code
defaults:
_controller: FrameworkBundle:Redirect:urlRedirect
path: /code
permanent: true
2 Via redirect() method in a custom controller
As explained here.
class RedirectsController extends Controller {
/**
* #Route("/codes")
*/
public function codesAction() {
return $this->redirect('/code', 301); // redirect /codes to /code
}
}
When I talk about differences I mean things like performance, ease of use and maintainability.
Thanks.

In the first case you don't need to create a controller. You can manage everything from the configuration, and this is a convenience.
The redirect will be made by RedirectController. In terms of performance there is no difference between the two methods.
If what you have to do is redirect then go with the first method.

The thing is your first solution will redirect without using a specific controller, using only configuration, whereas your second solution will do your action and then redirect. These are two different use cases and they are not the same.

Related

Is there a way to check controller parameters before the controller method?

My controller code has more lines to validate the received parameters than the real function code and I was wondering if there is a way to do this validations outside the controller method.
I have checked the Symfony docs but I could not found anything. I was thinking in something like a listener but just for that method.
Thank you guys.
EDIT: I'm aware about route requirements. I'm looking for a place to inject my own code.
EDIT: Added a little snippet.
public function searchAddressAction($radius, $page){
if ($radius < 5 || $radius > 50) {
throw $this->createNotFoundException('Radius not valid');
}
if ($page <= 0) {
throw $this->createNotFoundException('Page not found');
}
EDIT 3: This seems to be the way but I can't make it work (thanks to #dlondero):
search_address:
path: /{address}/{radius}/{page}
defaults:
_controller: AppBundle:Default:searchAddress
radius: 20
page: 1
options:
expose: true
requirements:
radius: \d+
page: \d+
condition: 'request.get("radius") == 50 '
Besides the default route requirements, there are 2 options to do some extra checks if a request should be passed through to a Controller.
Create a custom route loader.
http://symfony.com/doc/current/routing/custom_route_loader.html
This can be very useful if you want to get route requirements from the database for example.
Conditions (Might be what you're looking for)
https://symfony.com/doc/current/routing/conditions.html
This is using the expression language https://symfony.com/doc/current/components/expression_language/syntax.html
I don't think you can use the parameters name in here, but you can access the query in the request, which would for sure meet the requirements of the path.
If both of these are not working, than the validation has to be done in the Controller.
You can of course create a class to do the validation, and in your controller you use that class so you only have to call 1 method to do the validation.
I don't recommend a listener for this, as it would be called for all requests, and then has to do a check if it should do the validation.
Besides that it's performance wise not preferable, it doesn't make sense to do this kind of validation in a listener, so if someone else would work on your code, he has to dig in weird places to find out why a controller returns a 404, but still matches the route.
You probably are looking for kernel.request event. Then you could have your listener/subscriber and check what you need to check.

Symfony (a bit more dynamic ?) routing

I am new to symfony. As an exersice I`m trying to make some basic cms.And I was wondering is this aproach of routing wrong:
/**
* #Route("/back-office/", name="back-office")
*/
public function indexAction(Request $request,$page="")
{
switch($page){
case "":
return $this->render('CmsBundle:BackOffice:index.html.twig');
break;
default:
return $this->render('CmsBundle:BackOffice:site-map.html.twig');
break;
}
}
This is my yaml confing:
back_office_pages:
path: /{page}
defaults: { _controller: CmsBundle:BackOffice:index}
By using this aproach I wont have to configure each route in the yaml file. Since routes may vary. But I am not quite sure this is the symfony way of doing things so I decided to ask for advice..
What I`m trying to achive:
Lets say we have a user that have less back-end programing expirience or not at all and he stumbuled upon the CMS. The goal is to add front end pages using some user interface. Then we store the pages(slug) in the database. In the index action we retrive this data. From the database we can also assing template to a page (we need the user to have at least some html+css+twig).
So what we do is get the pages that user added :
ex : Gallery, Contacts
we check the request url
and if the page requested is in the array from the database we return the template related to the page.
NOTE:
If you disagree with this method please do not bash me but eplain why is this wrong. Because as I said I am still new with the framework.
Try setting your routing to:
back_office_pages:
resource: "#CmsBundle/Controller/"
type: annotation
to set up Routing Annotations inside your CmsBundle.
Then, your action should be working using the url "/back-office/{page}"

Dynamic action for route in Symfony 2.x (part of the url)

Is it possible to define a route in Symfony 2.x that dynamically resolves the action based on part of the route ?
Example :
rest_localite:
path: /rest/localite/{_action}
defaults: { _controller: ApplicationLocaliteBundle:Rest:{_action}, _format: json }
Thank you very much
This was considered bad practice as it exposes internal parts of the application and last I heard they removed it.
If you are doing this to save time you might want to look at the #Route annotations for actions, it is less of a pain.
But if you really cannot do without dynamic actions calls and do not mind the risk you could try passing the action's name as a parameter to a single controller method that then calls the appropriate method.

Symfony2 / routing / use parameters as Controller or Action name

Is it possible to route to a controller/action using given parameters ?
For example :
my_custom_route:
pattern: /{controller}/{action}
defaults: { _controller: AcmeDemoBundle:[controller]:[action] }
I would like [controller] and [action] to be replaced by given route's parameters values.
I.E : http://www.somedomain.com/Content/add should call action "addAction" of controller "ContentController" in bundle "AcmeDemoBundle"
Yes you can do so however it is not recommended. What would you do in future of you had to refactor your code and your controller / action had to change? You may break links and functionality along with possibly losing search engine optimization that may have been done for that particular route.

Symfony2 output any HTML controller as JSON

I have a website completed that was created in Symfony2 and I now want a lot of the features of the site to now be made available in a mobile app.
My idea is by appending a simple URL variable then it will output all the variables of the relevant page request in JSON.
So if I connect to
www.domain.com/profile/john-smith
It returns the HTML page as now.
But if I go to
www.domain.com/profile/john-smith?app
Then it returns a JSON object of name, age and other profile info.
My app code then receives the JSON and processes.
I can't see any security issues as it's just really the variables presented in JSON and no HTML.
By doing the above I can create all the app code and simply make calls to the same URL as a web page, which would return the variables in JSON and save the need for any more server-side work.
The question is: How would I do this without modifying every controller?
I can't imagine an event listener would do it? Maybe I could intercept the Response object and strip out all the HTML?
Any ideas as to the best-practice way to do this? It should be pretty easy to code, but I'm trying to get my head around the design of it.
There is a correct way to configure the routes for this task
article_show:
path: /articles/{culture}/{year}/{title}.{_format}
defaults: { _controller: AcmeDemoBundle:Article:show, _format: html }
requirements:
culture: en|fr
_format: html|rss
year: \d+
However, this would still require you to edit every Controller with additional control structures to handle that output.
To solve that problem, you can do two things.
Create json templates for each template you have, then replace html in template.html.twig with template.'.$format.'.twig. (Be careful to ensure users can't pass a parameter without validation in the url, this would be a major security risk).
Create your own abstract controller class and override the render method to check the requested format and provide output based on that.
class MyAbstractController extends Symfony\Bundle\FrameworkBundle\Controller\Controller
{
public function render($view, array $parameters = array(), Response $response = null)
{
if($this->getRequest()->getRequestFormat() == 'json')
{
return new Response(json_encode($parameters));
}
else
{
parent::render($view, $parameters, $response);
}
}
}
NOTE The above code is a prototype, don't expect it to work out of the box.
I personally would deem the second method more correct, because there is no duplication of code, and less security concern.

Resources