Say that I have to following 2 routes in this order:
Zip:
url: home/:zip
param: { module: home, action: results }
State:
url: home/:state
param: { module: home, action: results }
and I use a route such as:
'#State?state=CA'
Why does it resolve to the Zip route?
I thought when you specified the route name explicitly: '#State' that it did not parse the entire routing file and just used the specific route you asked for.
I would like to be able to use the same action to display data based on the variable name (zip or state) I don't want to have to create the same action (results) twice just to pass in a different parameter.
You need to add requirements so that it will recognize the different formats
Zip:
url: home/:zip
param: { module: home, action: results }
requirements: { zip: \d{5} } # assuming only 5 digit zips
State:
url: home/:state
param: { module: home, action: results }
requirements: { state: [a-zA-Z]{2} }
That should fix it, although I agree with you that when you use a route name in a helper it should use the named route.
the problem here is that both routing rules resolves to somewhat same url ( /home/) and when generating links it uses correct named route to generate url.
when you click on that generated url( for example /home/CA) withouth requirements addition it will match the first rule in routing.yml file that matches and that is your "Zip" route.
just to explain what is happening.
It does use the named route. The issue is that your URLs are the same (the paramater name is irrelevant) so when you load the URL in your browser, the first route to match will always be Zip as there is no way for Symfony to know which one you want.
Adding requirements: is the way to go.
Related
How to setup default routing in Symfony2?
In Symfony1 it looked something like this:
homepage:
url: /
param: { module: default, action: index }
default_symfony:
url: /symfony/:action/...
param: { module: default }
default_index:
url: /:module
param: { action: index }
default:
url: /:module/:action/...
I was looking through the cookbook for an answer to this, and think I've found it here. By default, all route parameters have a hidden requirement that they match any character except the / character ([^/]+), but this behaviour can be overridden with the requirements keyword, by forcing it to match any character.
The following should create a default route that catches all others - and as such, should come last in your routing config, as any following routes will never match. To ensure it matches "/" as well, a default value for the url parameter is included.
default_route:
pattern: /{url}
defaults: { _controller: AcmeBundle:Default:index, url: "index" }
requirements:
url: ".+"
I don't think it's possible with the standard routing component.
Take a look to this bundle, it might help :
https://github.com/hidenorigoto/DefaultRouteBundle
// Symfony2 PR10
in routing.yml:
default:
pattern: /{_controller}
It enables you to use this kind of urls: http://localhost/MySuperBundle:MyController:myview
Symfony2 standard routing component does not support it, but this bundle fills the gap Symfony1 left:
https://github.com/LeaseWeb/LswDefaultRoutingBundle
It does what you expect. You can default route a bundle using this syntax:
FosUserBundle:
resource: "#FosUserBundle"
prefix: /
type: default
It scans your bundle and automatically adds routes to your router table that you can debug by executing:
app/console router:debug
Example of automatically added default routes:
[router] Current routes
Name Method Pattern
fos_user.user.login_check ANY /user/login_check.{_format}
fos_user.user.logout ANY /user/logout.{_format}
fos_user.user.login ANY /user/login.{_format}
...
You see that it also supports the automatic "format" selection by using a file extension (html, json or xml).
Here is an example: http://docs.symfony-reloaded.org/master/quick_tour/the_big_picture.html#routing
A route definition has only one mandatory parameter pattern and three optionals parameters defaults, requirements and options.
Here's a route from my own project:
video:
pattern: /watch/{id}/{slug}
defaults: { _controller: SiteBundle:Video:watch }
requirements: { id: "\d+", slug: "[\w-]+"
Alternatively, you can use #Route annotation directly in a controller file. see https://github.com/sensio/SensioFrameworkExtraBundle/blob/master/Resources/doc/annotations/routing.rst
As for the default routes, I think Symfony2 encourages explicit route mapping.
Create a default route is not a good way of programming. Why? Because for this reason was implemented Exception.
Symfony2 is built just to do right things in the right way.
If you want to redirect all "not found" routes you should use exception, like NotFound404 or something similar. You can even customise this page at your own.
One route is for one purpose. Always. Other think is bad.
You could create your own bundle that handled all requests and used URL parameters to construct a string to pass to the controller's forward method. But that's pretty crappy, I'd go with well defined routes, it keeps your URLs cleaner, and decouples the URL and controller names. If you rename a bundle or something, do you then have to refactor your URLs?
If you want to create a "catch all", your best bet would be to hook on the KernelEvents::EXCEPTION event. This event gets triggered whenever an Exception falls through to the HttpKernel, this includes the NotFoundHttpException thrown when the router cannot resolve a route to a Controller.
The effect would be similar to Symfony's stylized 404 page that gets rendered when you send the request through app_dev.php. Instead of returning a 404, you perform whatever logic you're looking to.
It depends... Some of mine look like this:
api_email:
resource: "#MApiBundle/Resources/config/routing_email.yml"
prefix: /
and some look like
api_images:
path: /images/{listingId}/{width}/{fileName}
defaults: { _controller: ApiBundle:Image:view, listingId: null, width: null, fileName: null }
methods: [GET]
requirements:
fileName: .+
I'm trying to find a way get the symfony 1.4 to render the page:
/detail/id/1
when url called is:
/?url=/detail/id/1
Any ideas? Been googling around but so far haven't found the solution for it. Any ideas? I know it could be done with rewrites but i hoped i can do it through routing.yml somehow.
You can manually add that line into your routing.yml, in your case I would do (i suppouse that the module is detail and the action is id):
detail_id:
url: /?url=/detail/id/:id
param: { module: detail, action: id }
requirements:
id: \d+
Getting the id from the action with $this->getParameter('id')
I'm finishing the API of our web service. Now I'm thinking on how to make the route changes, so if we decide to make a new version we don't break the first API.
right now:
url: /api/:action
param: { module: api, action: :action }
requirements:
sf_format: (?:xml|json)
what i've thought:
url: /api/v1/:module/:action
param: { module: api1, action: :action }
requirements:
sf_format: (?:xml|json)
url: /api/v2/:module/:action
param: { module: api2, action: :action }
requirements:
sf_format: (?:xml|json)
That's easy, but the perfect solution would be to have the following kind of route
# Automatically redirects to one module or another
url: /api/v:version/:module/:action
param: { module: api:version, action: :action }
requirements:
sf_format: (?:xml|json)
any ideas on how to do it? what do you recommend us to do?
thanks!
I think the approach of having 2 routes, one with v1 on it and another with v2 is the better solution. It may sound like redoing work, but if u start to think, the reason to have to versons is that the first is imcompatible with second. So, mix the 2 logics would be an overkill. If you think in some day in the future when u can have 3 version, how do you think your logic will look like?
The better solution is to make the both separate, so if u need to stop doing support for version 1 it will be easy as remove the file for version 1. =)
How about just use the old routing rules and append .xml1/.xml2/.json1/.json2 to the end? That way you can reuse your current modules and only need to create a new view ("indexSuccess.xml1.php").
Or create a new routing class?
You should probably create a custom route collection, as shown here.
This would allow you to match any routing needs you have. You could move the version logic to the route class and route collection class.
I have a defined route that displays a dynamic page:
page_show:
url: /:domain_slug/:slug
class: sfPropelRoute
options:
model: Page
type: object
method: doSelectByDomain
param: { module: page, action: show }
requirements:
sf_method: [get]
This works great, but now I want my homepage URI to route to a specific page. To do that, I assume that I have to pass the :domain_slug and :slug values of the page I want to display as the homepage. That's fine, but I can't seem to track down any documentation or example that shows me how to go about doing that.
Is it possible to specify specific variable values in a route? In this case, I want to pass :domain_slug => portal, :slug => dashboard (that syntax doesn't work, btw). Essentially, I want to create a homepage route that looks something like this:
homepage:
url: /
class: sfPropelRoute
param: { module: page, action: show, array( :domain_slug => portal, :slug => dashboard ) }
options:
model: Page
type: object
method: doSelectByDomain
But different enough that it, you know, works. :-) I suppose I could create a simple route to a different method, modify the request parameters manually and forward to the executeShow() method, but that's a hack I'd rather avoid if a more elegant solution is available.
Thanks.
You can define values in the param key of the route... for example:
homepage:
url: /
class: sfPropelRoute
param: { module: page, action: show, domain_slug: portal, slug: dashboard}
options:
model: Page
type: object
method: doSelectByDomain
At least thats how it works with a non propel/doctrine route. I assume it should be the same with any type of route in the framework.
I never found a way to do this that worked (or maybe I just couldn't manage to do it correctly). My solution was to create the route and pass it through a custom method that does the work to specify the appropriate page details:
homepage:
url: /
class: sfPropelRoute
options:
model: Page
type: object
method: doSelectHomepage
param: { module: page, action: show ) }
requirements:
sf_method: [get]
The doSelectHomepage() method does all of the work I was hoping I'd be able to do by hardcoding values in the route itself.
Actually it did work, it was just the order in which the routes were defined. The first answer is correct. It may have worked for you if you added "homepage" rule BEFORE the "page_show" rule. So maybe Symfony isn't as stupid as I thought...No, no, it is. It's just not that bad.
I've set a website up. If I try and click on a link such as register I get the following error:
404 | Not Found | sfError404Exception
Empty module and/or action after parsing the URL
"/trevelyan.alumni/register" (/).
The links are generated using
<?php
print link_to( 'Register', 'register/index' );
?>
And I have a 'register' module in apps/frontend/modules/register.
I'm quite new to Symfony, any help is appreciated!
routing.yml:
# default rules
homepage:
url: /
param: { module: home, action: index }
default_index:
url: /:module
param: { action: index }
default:
url: /trevelyan.alumni/:module/:action/*
I think that your problem is that you're running symfony out of a "sub-site" instead of directly off of the "root" url (http://www.dur.ac.uk/trevelyan.alumni instead of http://www.dur.ac.uk/). I think the easiest solution would be to add trevelyan.alumni to the front of all your urls in routing.yml.
For example, for the default route, instead of
default:
url: /:module/:action/*
use
default:
url: /trevelyan.alumni/:module/:action/*
Read Steven Oxley, but try this as well :
Check you have at least an action class in your module dir with the proper name (symfony is case sensitive, and this is very tricky).
If you do, check that the default action (in the module config files) is one of the action class in your module.
Don't forget to clear cache every time you change a config file.
I managed to fix this by editing the symfony controller files to use the $_SERVER variables to pick a module from, if one was not found.
at the end of your routing.yml file:
homepage:
url:
param: { module: main, action: index }
default:
url: /:module/:action/*
and donĀ“t forget to clear the cache afterwards ;)
Just a quick note, for the routing change(s) to take effect, you must run symfony clear cache:
./symfony clear-cache
you should remove a dot from your matching url for route because of default routing rules
change your default route to:
default:
url: /trevelyan_alumni/:module/:action/*
and that should work. note that dot(.) is replaced with _
I had upgraded from symfony 1.2 to 1.4, and was having this problem. At the end of the day, basically the config files have all changed enough to the point that routing somehow broke. Going through the app config files and comparing / updating them against the "new app" templates found in lib/vendor/symfony/lib/config/config (or where ever you are keeping symfony) fixed this issue.