Coder Social home page Coder Social logo

Catch all route about route HOT 17 CLOSED

thephpleague avatar thephpleague commented on July 22, 2024
Catch all route

from route.

Comments (17)

thinsoldier avatar thinsoldier commented on July 22, 2024 2

As for the regex, yes you can define directly in the route, something like this should suffice /{any:(.*)}.

$route->map('GET', '/{any:(.*)}', 'FOUROHFOURController::FOUROHFOUR');

Fatal error: Uncaught exception 'FastRoute\BadRouteException' with message 'Regex "(.*)" for parameter "any" contains a capturing group' 

from route.

patrickheeney avatar patrickheeney commented on July 22, 2024 1

@philipobenito In that case, maybe all we need is some documentation? I first searched there and then eventually lead to here. OP seemed to have the same issue.

Some follow up questions after looking at wildcard routes:

  1. How should we format the regex to have it match everything?
  2. I'd like to add the regex right into the route without the pattern matcher, but is this possible?
  3. How do we ensure the catch all runs last? If we have various parts of the systems adding routes via the DI, we can't guarantee the order they are defined in. We would need a sort order or something to say this route should run after all the others.

I personally don't care how it is implemented (or if it already is), just looking for an easy expressive way to define a catch-all route. I can't speak for everyone else, but I believe every router I have looked at so far has implemented this because there must be a use case for it.

I think the ability to add our own logic in here would be suitable. Maybe something like this:

protected function handleNotFound()
    {
        if ($this->getStrategy()->handles(Interface::NOTFOUND) {
            return $this->getStrategy()->handle(Interface::NOTFOUND);
        }

        throw new NotFoundException;
    }

That way the strategy can take care of handling the exception and the RestfulStrategy would no longer be hard-coded into the Dispatcher. We could then add our own CatchAll strategy which throws a NotFoundException after we have performed some custom logic. It wouldn't effect the router at all. This needs more then a few seconds thought, but that is what initially appeals to me.

from route.

hvt avatar hvt commented on July 22, 2024 1

As for the regex, yes you can define directly in the route, something like this should suffice /{any:(.*)}.

$route->map('GET', '/{any:(.*)}', 'FOUROHFOURController::FOUROHFOUR');

Fatal error: Uncaught exception 'FastRoute\BadRouteException' with message 'Regex "(.*)" for parameter "any" contains a capturing group' 

Came here by search, and although it's an old closed issue, I think it might help other people too. This does work for catching all routes when using FastRoute:

$route->map('GET', '/{any:.*}', 'FOUROHFOURController::FOUROHFOUR');

from route.

felixkiss avatar felixkiss commented on July 22, 2024

Oh, here is a thought, maybe I can catch the 404 exception. I will try to get it to work that way.

from route.

felixkiss avatar felixkiss commented on July 22, 2024

It works, I did it this way:

try
{
    $response = $dispatcher->dispatch(
        $request->getMethod(),
        $request->getPathInfo()
    );

    $response->send();
}
catch(NotFoundException $exception)
{
    // handles everything else, e.g. POST /foo
    $response = new Response;

    // do whatever

    $response->send();
}

from route.

hannesvdvreken avatar hannesvdvreken commented on July 22, 2024

Rubber ducking with a github issue. 👌

from route.

philipobenito avatar philipobenito commented on July 22, 2024

@felixkiss yes, that's how I do it currently, considering building a strategy that will handle that but nothing confirmed yet.

from route.

patrickheeney avatar patrickheeney commented on July 22, 2024

Can this be re-opened. I am interested in this as well. Converting existing app to SPA and need to route all requests to the SPA now.

from route.

philipobenito avatar philipobenito commented on July 22, 2024

@patrickheeney The main problem here is for us to assume how the user will want to deal with this. I have a few things planned for v2 which will take these considerations in to account but some solid code examples from such as yourself for exact use cases would be helpful.

from route.

patrickheeney avatar patrickheeney commented on July 22, 2024

@philipobenito Here are some suggestions:

Regex way:

Route::any('(.*)', function($page) {
    dd($page);
});

Laravel way:

Route::any('(:any)/(:all?)', function($first, $rest=''){
    $page = $rest ? "{$first}/{$rest}" : $first;
    dd($page);
});

Maybe something event related? Catch a RouteNotMatched route and be able to easily forward the call onto another route?

Maybe a catch-all strategy that only gets called after routes do not match in a last attempt to get a response?

My exact use case is forwarding all requests to my singe page app route handler. This provides a way to use external urls like /app/settings which then get forwarded to my SPA router to pull up the relevant "page". We will have other routes in our system around the user registration and some business logic so I would expect these routes to still work and any others that do not get routed to the catch-all.

from route.

patrickheeney avatar patrickheeney commented on July 22, 2024

To give you some more context, here are a few others:

Symfony, More

catch_all:
    path:     /{catchall}
    defaults:
        _controller: YourProjectBundle:Index:catchAll
    requirements:
        catchall: ".+"

Klein

*                    // Match all request URIs
[*]                  // Catch all (lazy)
[*:trailing]         // Catch all as 'trailing' (lazy)
[**:trailing]        // Catch all (possessive - will match the rest of the URI)

$klein->respond('*', function ($request, $response, $service) { $service->render('header.phtml'); });

Aurora

$router->add('catchall', '{/controller,action,id}')
    ->addValues(array(
        'controller' => 'default',
        'action' => 'index',
        'id' => null,
    ));

from route.

philipobenito avatar philipobenito commented on July 22, 2024

My problem is that whilst I do see a use case, I don't necessarily see a "good" use case if that makes sense?

You could actually achieve this via a pattern matcher and a regular expression (http://route.thephpleague.com/wildcard-routes/). I'm just not sure that I'd personally recommend it. I'd be happy to change my view though if somebody can give me a good reason why this is useful other than "It's easier" which have been the only reasons I've been given for it so far.

from route.

philipobenito avatar philipobenito commented on July 22, 2024

@patrickheeney sorry, only just seen your first comment with use cases, will ponder it and get back to you.

My initial reaction for your specific use case though would be to advise the use of a custom route strategy. This is much better as you're handling this with logic rather than handing off to a controller to handle it.

from route.

philipobenito avatar philipobenito commented on July 22, 2024

So how about this, strategies could expose not only the dispatch method but how to handle not found and not allowed? That would allow you to catch and do whatever you like. This is something I'd definitely be interested in doing.

As for the regex, yes you can define directly in the route, something like this should suffice /{any:(.*)}. Defining regex was in the docs originally but it's gone now, apologies for that, but it is in the new documentation that will be pushed shortly.

As for running the catch all last, that's not how the matching works in FastRoute (underlying library), it pulls matches out of a larger regular expression, this is why it's fast and this is why it's not as simple as with most routers to provide a catch all. Also the idea of running it last would suggest it is not actually a catch all but a catch everything else, this has to be specific as if I were to implement it there would have to be that distinction. However, catch everything else would also be possible by building a regular expresion to ignore the matches that you need to define separately.

Again, because other routers implement this is not for me the best reason to implement it here. Defining your routes explicitly is good practice, but I understand from your perspective of a SAP that it's a little different.

What I think is the best way forward with this is for v2 (being developed now with the same functionality but depending on PSR-7 instead of a concrete implementation of Symfony Http Foundation and a few small additions) is to expose the behaviour around not found and not allowed to the Strategy with a default behaviour of allowing the exceptions to bubble out. This would easily allow you to build a SAP Strategy, or for me to even include one in the package.

from route.

patrickheeney avatar patrickheeney commented on July 22, 2024

I think it sounds like a great plan. As there is a distinction between catch-all and catch-everything-else, I think you covered the use case for the former.

Should anything be done about the latter? Or should we do like the OP and catch the NotFound exception and handle it however we need. The alternative would probably be a way to $router->addStrategy(new NotFoundStrategy, [Interface:NOTFOUND]); so that you can bind strategies but only for certain criteria?

Also my point about other routers, was just to imply that the other routes probably have documentation on use cases for this feature. I personally have not done a lot of research on different use cases as I can only speak to my own. Wasn't trying to imply that you follow the group.

from route.

philipobenito avatar philipobenito commented on July 22, 2024

Oh I get that, long day that's all, if I ever sound a little to the point it's usually because I'm quite busy, never mean anything by it, massively appreciative of all discussion.

As for the catch-everything-else situation, I think by exposing the not found functionality to a strategy this could be handled quite elegantly with a custom strategy without the need for any exception catching in the front controller/bootstrap.

I think by doing that we are essentially making the router completely extensible but with a few defaults thrown in there for the 99%ers.

from route.

thinsoldier avatar thinsoldier commented on July 22, 2024

Where can I find the documentation for things like $request->getMethod() and $request->getPathInfo() ?

from route.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.