Route with optional parameter is not working in Symfony 2 - symfony

I am experiencing some issues with optional parameters in my routes. I think I did it properly according to the documentation but still it is not working.
So I have the following route defined:
test_wizard:
pattern: /test/wizard/{testName}/{step}/
defaults: { _controller: TestBundle:Wizard:wizard, step: 1 }
and would like the route to be able to be called by /test/wizard/someTestName and then fill in the step parameter with the default value of 1 but everytime I call the route just with the test name I get the following instead:
No route found for "GET /test/wizard/someTestName"
When I call the route by /test/wizard/someTestName/1/ itworks just fine. Why is my defined default value for step not working? Any suggestions? Thanks.

It is not possible to make a parameter optional if you have a character after it (/ in your case). You have to define two routes:
test_wizard:
pattern: /test/wizard/{testName}
defaults: { _controller: TestBundle:Wizard:wizard }
test_wizard_optional:
pattern: /test/wizard/{testName}/{step}/
defaults: { _controller: TestBundle:Wizard:wizard, step: 1 }

Related

How do I force a 404 from the symfony routing in YML without specifying a custom controller?

Problem to solve
I want to force to trigger a 404 for a certain specific route in symfony, without having to specify a custom controller that just throws the exception, and before the router continues to explore the rest of the routing file.
Can I say that in the routing.yml file for a specific route?
Context
I have this routing for form submitting in my travel agency:
POST /submit/{submitterForm}
where submitterForm can only take 2 values: purchase-trip and contact depending on if the visitor submits a form in a page where he is visiting a trip or from the contact page. For example POST /submit/contact would be valid.
I have this other route:
GET /{destinationSeoUri}/{tripSeoUri}
to display a specific trip for a destination. For example GET /thailand/trip-bangkok-beaches would be valid.
Limiting values from the router
This is the relevant extract of my routing.yml:
submit:
path: /submit/{submitterForm}
methods: [ POST ]
defaults: { _controller: AppBundle:DataSubmission:submit }
requirements:
submitterForm: purchase-trip|contact
trip:
path: /{destinationSeoUri}/{tripSeoUri}
methods: [ GET ]
defaults: { _controller: AppBundle:Trip:trip }
What I want
For any POST request with an invalid value of {submitterForm} in the route /submit/{submitterForm} I want that the system returns a 404 Not Found
It does not happen now because when the router does not match the submit route pattern, it still falls down to the next ones and then matches the trip pattern.
Then, the system says "okey, I have a route that matches, instead, this is only allowed for GET, so I'll respond a 405 Method not allowed".
This would hold true for something like POST /thailand/trip-bangkok-beaches but I want to specifically signal the client that if the POST matches the /submit/any-invalid-form-submitter-name it is then a Not Found.
Initial solution
To do so, I've inserted, in order, in the middle of the previous two, a catch-all for /submit/* like in this routing excerpt:
submit:
path: /submit/{submitterForm}
methods: [ POST ]
defaults: { _controller: AppBundle:DataSubmission:submit }
requirements:
submitterForm: purchase-trip|contact
submit_fallback:
path: /submit/{submitterForm}
methods: [ POST ]
defaults: { _controller: AppBundle:DataSubmission:notFound }
trip:
path: /{destinationSeoUri}/{tripSeoUri}
methods: [ GET ]
defaults: { _controller: AppBundle:Trip:trip }
This way, requesting to POST /submit/any-invalid-form-submitter-name is matched by the submit_fallback route.
The controller
The controller is a pretty simple "on-liner":
{
throw new NotFoundHttpException();
}
Preferred solution
I think I'm looking for something similar to this:
submit_fallback:
path: /submit/{submitterForm}
methods: [ POST ]
status: 404
So, questions
Is it possible for me to tell the submit_fallback something like: hey guy you don't need a _controller just because you have to send a 404 Not found (or any other status I would want) and nothing else.
If so, how?
Just add requirements onto your other route so that destinationSeoUri cannot equal submit. This should force that route to not match, and throw the 404 instead of the 405 error.
trip:
path: /{destinationSeoUri}/{tripSeoUri}
methods: [ GET ]
defaults: { _controller: AppBundle:Trip:trip }
requirements:
destinationSeoUri: "^(?!submit$)"

Define route without ending slash when importing route in Symfony 2.5?

In file: HardCoreMore/HRAPIBundle/Resources/config/routing.yml
I have imported route like this:
hr_api_company:
resource: "#HRAPIBundle/Resources/config/routing/company.yml"
prefix: /company
And in file: HardCoreMore/HRAPIBundle/Resources/config/routing/company.yml
I have defined route for creating company like this:
hardcoremore_hr_api_company_create:
pattern: /
defaults: { _controller: HRAPIBundle:Company:create }
methods: [POST]
Now the route is matched with following url:
POST company/
but it is not matched when I called it with:
POST company
How can I define route without ending slash when importing route and prefixing it?
this is not possible, see : https://github.com/symfony/symfony/issues/4322
I hope this has helped

Symfony2 route based on host. With parameters

I have followed the instructions here:
http://symfony.com/doc/current/components/routing/hostname_pattern.html
To make the route based on the host. However I want to use parameters instead of hard coding. The documentation says you can use service parameters, but I seem to be having trouble getting the parameters to work.
Here is the code from routing.yml:
rc_course_new:
pattern: /course/new
host: "{ domain }"
defaults: { _controller: CoursesRCWizardBundle:Wizard:new }
requirements:
domain: "%rc_domain%"
And here is the code from services.yml:
parameters:
rc_domain: my.domain.com
I get this error (looks like it is not picking up the parameter but seeing it as a hard code):
Oops! Google Chrome could not find { domain }
Managed to fix this:
In the routing:
rc_course_new:
pattern: /course/new
host: "%rc_domain%"
defaults: { _controller: CoursesRCWizardBundle:Wizard:new }
In the services (might work better in the parameters file) file:
parameters:
rc_domain: my.domain.com

Symfony2 i18n routing - defining an array of requirements

Is it possible to define an array of locales used in Symfony2 routing rules, so that I won't have to repeat it over and over in every route and alter it for each route separately in case I change the supported languages list?
I know it's very easy to do a quick search & replace in routing.yml, but the issue's scope could be easily expanded so that it provokes a question like this: is it possible to provide this locale array externally (i.e. to have it read from a database)?
For clarification - here is an example of what I have now:
page_show:
pattern: /{_locale}/page/{slug}
defaults: { _controller: myCompanymyBundle:Cms:pageShow }
requirements:
_locale: en|pl
slug: "[^,]+"
news_archive:
pattern: /{_locale}/news/archive
defaults: { _controller: myCompanymyBundle:Cms:newsArchive }
requirements:
_locale: en|pl
And here is an example of what I'd like to have:
page_show:
pattern: /{_locale}/page/{slug}
defaults: { _controller: myCompanymyBundle:Cms:pageShow }
requirements:
_locale: languages
slug: "[^,]+"
news_archive:
pattern: /{_locale}/news/archive
defaults: { _controller: myCompanymyBundle:Cms:newsArchive }
requirements:
_locale: languages
Where languages is an array, be it a YAML array or a PHP array provided externally; it's not really substantial.
This could be very helpful to further ease the configuration of the application I'm writing. I'd like to extract as much configuration as possible into the config.yml file. So that if I decide that, for instance, I want to add a new language quickly and I already support it in the business logic and templating layers, I just have to modify the languages array in config.yml and voila, it's done.
Thats something that bugs me every time. The only thing I could offer is to put your requirement params into app/config/parameters.yml
# src/App/Resources/config/routing.yml
sport:
pattern: /{_locale}/{sport}
defaults: { _controller: App:Vote:vote }
requirements: { _locale: %routing_locales%, sport: %routing_sports% }
# app/config/parameters.yml
parameters:
# routing requirement regex
routing_sports: 'hockey|football' # available sports so far
routing_locales: 'de|fr' # available locales so far

Symfony2 router - how to call annotation route

Simple case. In my all app I'm using Route annotation driver, defined in routing.yml as follows:
MyBundle:
resource: "#MyBundle/Controller/"
type: annotation
prefix: /someprefix
Some action in MyBundle's Ctrl controller looks like:
#Route("/{page}/{status}", name="default_action", defaults={"page" = 1, "status" = "ok"}, requirements={"page" = "\d+"})
public function defaultAction($page, $status) {...}
Now I want to make this action - default action when visiting my web page. I cannot use just #Route("/") because I'm prefixed. So I'm adding to routing.yml:
_welcome:
pattern: /
defaults: { _controller: MyBundle:Ctrl:default }
And there is where problem starts - Symfony2 is calling default controllers action not from annotation but just from action and I get error:
Controller "...:defaultAction()" requires that you provide a value for the "$page" argument (because there is no default value or because there is a non optional argument after this one).
So simply Symfony2 is not obtaining default values from #Route annotation.
Question is: how to call route for _welcome that is aware of #Route?
You've missed defaults in yml settings, should look like this:
_welcome:
pattern: /
defaults: { _controller: MyBundle:Ctrl:default, page: 1, status: ok }

Resources