thephpleague / route Goto Github PK
View Code? Open in Web Editor NEWFast PSR-7 based routing and dispatch component including PSR-15 middleware, built on top of FastRoute.
Home Page: http://route.thephpleague.com
License: MIT License
Fast PSR-7 based routing and dispatch component including PSR-15 middleware, built on top of FastRoute.
Home Page: http://route.thephpleague.com
License: MIT License
Hi, I'm not sure if this is implemented yet. Would be cool to have named routes.
What are your thoughts about supporting the PSR-7 request and response interfaces in the Request/Response strategy instead of a hard dependency on Symfony HTTP foundation?
I was not a fan of Front Controller pattern in PHP, but I am trying to force myself to follow the movement of open source frameworks. So I think FastRoute\cachedDispatcher could reduce the overhead of dispatching process as much as possible (of course, I know this is a premature optimization). I wonder, does league's route support it? I cannot found any declaration of that class in the source code.
Currently route requires league/container, however, it would be beneficial to support the container-interop project as to not create a hard dependency on the league/container project itself. I for one would prefer to utilize a supporting container-interop project instead in some cases. I believe that is a planned feature for league/container but ideally it would happen with v2 of container and the dependency would be lifted in v2 of route.
So, I've been looking at bringing in a PSR-7 middleware implementation, the front runner is Relay at the moment. With version two though I feel I've made a glaring mistake with the JsonStrategy
in not passing the response object off to the controller.
What I'd like to do is bump to version 3 and implement in a way that I'd be happy with, allowing per route and per group middleware on any strategy. As things stand, because of the issue with the JsonStrategy
I would probably have to provide a new middleware specific strategy to keep BC.
I suppose one of the benefits of bumping to v3 now is that the install base for v2 is still quite small so support would only have to be provided for a small amount of time rather than waiting and having to support it for much longer, and it would be a relatively simply upgrade guide.
Thoughts? @hannesvdvreken @localheinz @kayladnls
Is there a way to add a catch all route that deals with every request that doesn't match one of the other specified routes.
Something like this:
$router->addRoute(
'GET', '/foo',
function(Request $request, Response $response)
{
// handles GET /foo
}
);
$router->addCatchAllRoute(function(Request $request, Response $response)
{
// handles everything else, e.g. POST /foo
});
https://github.com/thephpleague/route/blob/master/src/Strategy/AbstractStrategy.php#L36
The new container is returned but not saved. Also, ContainerAwareTrait
could be used here.
Hello!
I just started to use this library after a long search for the perfect router class/framework/library for my project(s). And with the additions in V2 I think this is the perfect class for my needs!
But I only miss the documentation for the second version, I am now developing with help of the code and the unit tests. But I am sure that I miss some nice features this way :)
Has someone already started with early version of the documentation?
Also I would like to help with the documentation if needed, just let me know and I will see if I can help!
Kind regards,
Matthijs
The Request object from Symfony has a built-in property (attributes) for parameters from the route:
http://api.symfony.com/2.6/Symfony/Component/HttpFoundation/Request.html#createFromGlobals%28%29
The RequestResponseStrategy would have to be modified like this:
$request = $this->getContainer()->get('Symfony\Component\HttpFoundation\Request');
$request->attributes->add($vars);
$response = $this->invokeController($controller, [
$request,
$this->getContainer()->get('Symfony\Component\HttpFoundation\Response')
]);
What are your thoughts on this? I can do a pull request later for this if you want.
As the code only passes the Container instance down the chain to a Strategy, which itself only uses the get
method, it would make sense to not rely on a hard dependency of the League Container, and rather replace this dependency with a dependency on the Interop Container instead.
This would make the code much freer from having to use a container that developers may not be using, and increase uptake of the package.
Personally, I am a fan of Auryn Injector, and could very easily make a very simple bridge for Auryn to the package, if only it relied on the Interop Container instead of the League one.
I understand that a custom Strategy can be made that relieves the reliance, but still, an instance of a Container is still created and passed around that is not always required. Call me weird, but this just doesn't feel right to me.
Hi all,
I am trying v2 for my application. I really like the route groups, but I couldn't figure out a way to build nested route groups.
I tried to just simply nest it
$router = new RouteCollection($container);
$router->group('/admin', function($router) {
$router->map(...);
$router->group('/cms', function($router) {
$router->map(...);
$router->map(...);
});
});
But I get the error (for the nested group):
Fatal error: Call to undefined method League\Route\RouteGroup::group()
So I think nested routing is not supported, is this possible to implement?
Have you considered adding this feature? If it's something that you'd like to see added I could start working on a PR. I know it would be helpful for the work we're doing.
The link to "League\Container" is missing a 'u' in 'thephpleague'. Page: http://route.thephpleague.com/method-argument-strategy/
Current: https://github.com/thephpleage/container (404)
What it should be: https://github.com/thephpleague/container
In addition to strategies I would like to add middleware-like filters. A filter could be added to a filter collection of an route. A filter could be an invokable or callable. Filters are executed on dispatching a route. Filters are aware of request, response, route and passed dispatch vars.
First of all, thank you for sharing your amazing router!
I couldn't find any examples to use the v2, so I wonder if you can give me one.
Furthermore, PSR7 will be use?
What kind of PSR7 module do you recommend, if any?
I am in a hurry to use the next version in one of my project because the next version looks pretty better than the first release and I am searching a powerful router!
Thank you :)
This page describes how to get the router to work for one route.
Personally I think it would be a bit more useful to have an example which shows how to typically use the router, via the URL actually requested etc.
I was playing with this package and I found imposible to do it ... Is that intentional? if so ... why? I can't understand the disadvantage of having access to the service container inside a Controller.
I end up doing it overriding AbstractStrategy::invokeController
as in here but IMHO it should be accesible.
Thanks in advance and great package!!!
Is there a way to have more than one variable inside of one part of a url?
Something like this doesn't work for me:
$router->addPatternMatcher('wordStartsWithM', '(m|M)[a-zA-Z]+');
$router->addPatternMatcher('wordStartsWithQ', '(m|Q)[a-zA-Z]+');
$router->get('/test/{first:wordStartsWithM},{second:wordStartsWithQ}', function (Request $request, array $args) use ($mysqli) {
return ["This is just for debug" => "true", "first" => $args['first'], "second" => $args['second']];
});
My code above generates the following result for me:
[[]]
But it 'seems' like the routing is working, partially... Am I doing it wrong?
Is there any way to sneak PSR-7 diactoros default support in the 2.0.0 release? We can suggest the symfony bridge and the symfony/http-foundation to make it simple to support. If so, I'd be happy to do this work.
I'd like to see some integration with pipeline for modifying Response objects to assist with the purposes of (but not limited to)
Not suggesting that those be baked in, but if league/pipeline were to be integrated, those are the examples I'd like to see (except maybe that last one, I've yet to find a PHP-based less compiler that's fully feature matching).
There's no particular reason that league/container
is a hard dependency, as it is only required when using the "Class Method" type of dispatching. Instead of being a required dependency, it should be suggested. This would make it possible to avoid using league/container
completely for those of us that prefer a different DI implementation.
As we can set custom strategies. It might be a good implementation in setting a custom dispatcher or try to interface it. So it will possible to do what in this issue #25 has stated. I'm working on adapters in which I can replace route components with ease without rewriting code every time.
When I run composer require league/route
I get the following:
Problem 1
- Conclusion: don't install league/route 1.1.0
- don't install league/route 1.0.x-dev|install league/route dev-master
- Conclusion: don't install league/route dev-master
- Conclusion: don't install league/route 1.0.1
- Installation request for league/route ~1.0@dev -> satisfiable by league/route[1.0.0, 1.0.1, 1.1.0, 1.0.x-dev].
- Conclusion: remove nikic/fast-route v0.2.0
- league/route 1.0.0 requires nikic/fast-route ~0.3 -> satisfiable by nikic/fast-route[v0.3.0, v0.4.0].
- Can only install one of: nikic/fast-route[v0.3.0, v0.2.0].
- Can only install one of: nikic/fast-route[v0.4.0, v0.2.0].
- Installation request for nikic/fast-route == 0.2.0.0 -> satisfiable by nikic/fast-route[v0.2.0].
Thoughts?
in develop branch:
Strict standards: Declaration of League\Route\RouteCollection::addRoute() should be compatible with FastRoute\RouteCollector::addRoute($httpMethod, $route, $handler)
This package could not use the most current version of the league container?
tks
May I suggest the removal of the callable type hints in the development branch?
When I provide [ SomeClass::class, 'methodName' ]
as a handler (implying that SomeClass be resolved from the DI container), multiple warnings are raised saying that methodName should not be invoked as a static method (because it isn't static). I can work around the warnings by prepending the @
to the map statement, but I don't think that's a decent solution.
Worse even, when I provide 'SomeClass::methodName'
as handler (which should be legal), a fatal error is raised.
In RequestResponseStrategy.php
, when Symfony\Component\HttpFoundation\Request
is fetched from the League Container, if it is not already set in the container then it will initiate a largely useless Request object that contains none of the globals that HttpFoundation Request is normally initiated with.
I am not extremely familiar with Dependency Injection so I don't know what the ideal fix for this is in this package. When using Route in a project you can make a Service Provider for HttpFoundation or set it with $container->add('Symfony\Component\HttpFoundation\Request', Request::createFromGlobals());
, but it was quite unexpected to have to do so.
So I noticed in the docs it says you can set a custom container and pass it to the constructor of the route collection. There's no way to actually access the container from the route collection class though?
So what exactly is the point in passing a new container to the routecollection class? Maybe there's some confusion because the docs are vague on the usage and I can't seem to find anything anywhere questioning it.
Hi,
I have been using your fastroute extension and am enjoying it very much.
I was wondering if you would be interested in a Pull Request which adds a method to pass a configuration array?
/**
* Add a collection of routes from a configuration
* array
*
* @param array $routes
* @param \League\Route\Strategy\StrategyInterface $strategy
* @throws \League\Route\Exception\EmptyRoutingPassedException
* @throws \League\Route\Exception\MalformedRouteConfigurationException
*/
public function addRoutesFromConfig(
array $routes = [],
Strategy\StrategyInterface $strategy = null
) {
// Check if the array is empty
if (true === empty($routes)) {
throw new EmptyRoutingPassedException;
}
// Loop through each modules routing data
foreach ($routes as $module => $route) {
foreach($route as $name => $body) {
// Check configuration is passed correctly
if (
false === isset($body['method'])
|| false === isset($body['pattern'])
|| false === isset($body['controller'])
) {
throw new MalformedRouteConfigurationException(
sprintf(
'The route [%s] in the [%s] section has not been configured correctly',
$name,
$module
)
);
}
$this->addRoute($body['method'], $body['pattern'], $body['controller'], $strategy);
}
}
}
and then called like:
$routes = [
'demo_page' => [
'pattern' => '/demo/{name}',
'controller' => 'Demo\Controller\DemoController::index',
'method' => 'GET',
],
];
$router = new RouteCollection();
$router->setStrategy(new RequestResponseStrategy);
$router->addRoutesFromConfig($routes);
In terms of the exceptions, not sure if they are the best place for them as they are not Http exceptions but more argument exceptions?
Hi,
I have this code setup, I'm using symfony http request, but for routing/dispatching I'm using League/Route for a change..
I note something:
in the controller method (example below quoted), the $request object is empty - is this normal? Because I would expect that the initial $request object obtain (Request::createFromGlobals()) should have been reflected to Request in: public function action (Request $request, Response $response)
But this does not seem the case and the parameter being there is not having any use - defeating the purpose.
I am surely missing something here, anyone can help?
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class MyController
{
public function action (Request $request, Response $response)
{
print_r($request); // everything is empty including paramter bag for a POST !!
}
}
First of all, thanks for this fantastic package.
I was trying to implement a login and sort of a middleware to filter unauthenticate route requests.
So I use the Custom Strategy mentioned in the documentation.
I am not sure what code to put in the dispatch method. But, when I copy the code of RequestResponseStrategy's dispatch method, it did not show any errors.
But, in one Post request route - this error showed up - "Warning: array_map(): An error occurred while invoking the map callback in vendor\league\container\src\Container.php on line 495"
I am in the dark what to do next in this case.
Can you help me out to replicate the functionality if there is no Strategy used at all for the RouteCollection - so that I can have the same code in CustomStrategy's dispatch method ?
Simple example of this not working:
$test = new Test();
$router = new League\Route\RouteCollection;
$router->addRoute('GET', '/', [$test, 'index']);
$request = Request::createFromGlobals();
$dispatcher = $router->getDispatcher();
try {
$response = $dispatcher->dispatch($request->getMethod(), $request->getPathInfo());
$response->send();
} catch(Exception $e) {
echo $e->getMessage();
}
class Test
{
public function index(Request $req, Response $resp)
{
$resp->setContent("Testing");
return $resp;
}
}
Errors:
Warning: Illegal offset type in /var/www/source/vendor/league/route/src/RouteCollection.php on line 84
Warning: Illegal offset type in /var/www/source/vendor/league/route/src/RouteCollection.php on line 84
Warning: Illegal offset type in /var/www/source/vendor/league/route/src/Dispatcher.php on line 69
Warning: Illegal offset type in /var/www/source/vendor/league/route/src/Dispatcher.php on line 70
Catchable fatal error: Argument 2 passed to League\Route\Dispatcher::handleFound() must implement interface League\Route\Strategy\StrategyInterface, null given, called in /var/www/source/vendor/league/route/src/Dispatcher.php on line 73 and defined in /var/www/source/vendor/league/route/src/Dispatcher.php on line 85
Doing the following works as expected though:
$router->addRoute('GET', '/', 'test::index');
Both ways are valid callables, so this not working is weird.
I don't believe withMethodCall is part of Container v1.0 (which is currently required for this component). A solution to this would be upgrading to the latest version of Container.
This is regarding the develop branch
When I try to dispatch more than once on the same RouteCollection
instance, I get the following exception:
FastRoute\BadRouteException: Cannot register two routes matching "/" for method "GET" in /home/ubuntu/workspace/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php on line 55
If it's not intended to do so, this behaviour should probably be documented.
I can probably work around this with a factory of some sorts, but it would be neat if it was supported.
Minimal testcase:
use League\Route\RouteCollection;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\Uri;
$routes = new RouteCollection();
$routes->get('/', function() { return 'foo'; });
$routes->dispatch((new ServerRequest())->withUri(new Uri('/')), new Response());
$routes->dispatch((new ServerRequest())->withUri(new Uri('/')), new Response());
I added league/container:^2.0
as a dependency to my project on its own, then attempted to add league/route
as well (simply via composer require league/route
), and I receive a conflict due to Route requiring league/container:~1.0
.
I can eliminate the Container requirement so it will fall back to 1.0 resolution, but that's not ideal as I'd like to use the latest version of these packages. I know that Route 2.0 is around the corner sometime (and my project is slow moving, so I don't really care about fixing this immediately). Just figured I'd give you a heads up.
As someone who is starting to put individual components together to try and build an ideal "framework" for my projects, I'm happy to put some of these components through their paces and provide feedback and use where necessary, if I can be of any help.
Cheers ๐
FastRoute already have it inbuilt, so why not league/route as well :)
When registering a controller action and supplying an invalid method an exception is thrown as follows:
Catchable fatal error: Argument 1 passed to League\Route\Strategy\JsonStrategy::dispatch() must be callable, array given, called in <snip>/src/Route.php on line 79 and defined in <snip>vendor/league/route/src/Strategy/JsonStrategy.php on line 16
This occurs regardless of Strategy used.
A more descriptive exception needs to be thrown which more accurately describes that the method is invalid.
By default, trailing slashes are not handled - can this be IN by default please?
Example:
/page and /page/ should both be OK if only /page was added in RouteCollection
I am having a problem setting this up as there is no documentation of the location of the .htaccess in a project and data that should be in the .htaccess file
Hi,
What would be the best way to implement authentication to specified pages?
Currently I handle the authentication in the Controllers, but it would be nice if I could give a authentication 'flag' to a route (I think this is possible with middleware in Symfony routing?).
Is there already a build in way to do this? And if not, is this possible to do this with custom strategies? Or is there a better way to accomplish this?
Thanks in advance!
I am using @alexbilbie's Proton which uses this package for routing internally. My problem is that the original request object is not passed to the controller. When the dispatcher is called (with data originating from an already existing Request object), it creates a new Request which does not contain anything (not query params, etc).
I opened this issue here because I think it is rather an issue with routing than an issue with Proton itself. However, this still might occur because of improper use of router, so if this is a bug in Proton, I need some help to fix it.
Given I have a route /play/{someusername}
and I want the someusername
to be optional, is there a supported way of doing this - I'm currently using the Request Response strategy, and the route is just left unmatched when I make a request against /play
without any arguments.
Not so much of an issue as a question.
Is it possible to implement the following like laravel:
Route::group(['domain' => $domain, 'prefix' => 'version1'], function() {});
I was thinking strategies might help with this, but i'm not 100% sure how to. Any advice on where to look would be great!
Thanks.
Hello
I would like to pass the method as array like this:
$router->addRoute(array('GET', 'POST'), '/', function (Request $request, Response $response) {
// ...
});
Well this code is working but the documentation (and scrutinizer-ci) of the function addRoute
says that the datatype must be a string.
* @param string $method
But the internal call to the FastRoute addRoute function also accepts an array for $method.
* @param string|string[] $httpMethod
https://github.com/nikic/FastRoute/blob/master/src/RouteCollector.php
Would it be possible to fix the DocBlock for the parameter $method to this?
* @param string|string[] $method
I am using league/container
in my project and have this code to set up my container:
$container->add('Router', function () use ($container) {
$router = new RouteCollection($container);
$router->setStrategy(new RestfulStrategy);
// ... list of routes
return $router;
});
And then this code to dispatch the request:
$router = $container->get('Router');
$request = $container->get('Request');
$dispatcher = $router->getDispatcher();
$response = $dispatcher->dispatch($request->getMethod(), $request->getPathInfo());
The problem is that when my controllers are called with action($request)
the request is a new instance and not the request that was used to dispatch. I would suggest adding a method to RestfulStrategy
that would allow the request name to be set:
public function setRequest($request) { ... }
public function getRequest() { ... }
public function dispatch($controller, array $vars)
{
// ...
$request = $this->getRequest() ?: $this->getContainer()->get(...);
// ...
}
This would allow me to do the following, without having to use a FQCN in my container:
$container->set('DispatchStrategy', RestfulStrategy::class)
->withMethodCall('setRequest', ['Request']);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.