Search code examples
symfonyrouteshttpresponsehttp-status-codes

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?

Solution

  • 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$)"