We're exploring the Restler framework. What we need is a custom route like:
[host]/:sessionid/{class}/{method}?param1=x¶m2=y
For example, the Settings method in the Game class:
<?php
class Game {
function settings($session, $sound=TRUE, $music=TRUE){
//
}
}
?>
should map to http://hostname/12435635/game/settings?sound=x&music=y
We've managed to achieve it by hacking the routes.php file a bit, but as the file is auto-generated the idea is not very good. So, is it possible to create such routes without hacking the Restler's source or modifying the routes.php file?
First step is to remove class name from the URI. It can be achieved by modifying the addAPIClass statement
$r->addAPIClass('Game', '');
this changes the auto generated uri structure as follows
http://hostname/settings/12435635/?sound=x&music=y
Next step is to specify a route manually by adding a PHPDoc comment to the api method as shown below
<?php
class Game {
/**
* #url GET /:session/game/settings
*/
function settings($session, $sound=TRUE, $music=TRUE){
//
}
}
This will map to
http://hostname/12435635/game/settings?sound=x&music=y
This route will be added to routes.php every time it is generated in production mode :)
You may add more #url comments to create multiple routes to the same method
Related
Clean setup of Symfony 3 framework, added locale listener from here:
http://symfony.com/doc/current/cookbook/session/locale_sticky_session.html
Example action code:
/**
* #Route("/foo/")
* #Route("/{_locale}/foo/", name="foo", requirements={"_locale"="en|ru|tk"})
*/
public function fooAction(Request $request)
{
return new Response('true');
}
This syntax has to be repeated for every action. Is there a way to make it less verbose without using a Bundle? I'd like the requirements portion to reside in a config somewhere, if possible.
Ideally, I would like to move the defaults={"_locale"="en"}, requirements={"_locale"="%allowed_locales%"} part inside the Locale Listener, but from what I've tried, it seems the listener is called after the route has been matched, and so that is not possible, which is really a shame.
Yes, check out How to Use Service Container Parameters in your Routes which is linked from The Locale and the URL in the Symfony Translations documentation, and states:
Read How to Use Service Container Parameters in your Routes to learn how to avoid hardcoding the _locale requirement in all your routes.
You can essentially set those routes in a global parameter like so:
# app/config/config.yml
parameters:
app.locales: en|ru|tk
Then in your route annotations do the following:
/**
* #Route("/foo/")
* #Route("/{_locale}/foo/", name="foo", requirements={"_locale"="%app.locales%"})
*/
public function fooAction(Request $request)
{
return new Response('true');
}
I'm not sure why the documentation only shows that for defining routes in YAML / XML / PHP but it should work just the same using annotations.
In Laravel, we can get route name from current URL via this:
Route::currentRouteName()
But, how can we get the route name from a specific given URL?
Thank you.
A very easy way to do it Laravel 5.2
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1'))->getName()
It outputs my Route name like this slug.posts.show
Update: For method like POST, PUT or DELETE you can do like this
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST'))->getName()//reference https://github.com/symfony/http-foundation/blob/master/Request.php#L309
Also when you run app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST')) this will return Illuminate\Routing\Route instance where you can call multiple useful public methods like getAction, getValidators etc. Check the source https://github.com/illuminate/routing/blob/master/Route.php for more details.
None of the solutions above worked for me.
This is the correct way to match a route with the URI:
$url = 'url-to-match/some-parameter';
$route = collect(\Route::getRoutes())->first(function($route) use($url){
return $route->matches(request()->create($url));
});
The other solutions perform bindings to the container and can screw up your routes...
I don't think this can be done with out-of-the-box Laravel. Also remember that not all routes in Laravel are named, so you probably want to retrieve the route object, not the route name.
One possible solution would be to extend the default \Iluminate\Routing\Router class and add a public method to your custom class that uses the protected Router::findRoute(Request $request) method.
A simplified example:
class MyRouter extends \Illuminate\Routing\Router {
public function resolveRouteFromUrl($url) {
return $this->findRoute(\Illuminate\Http\Request::create($url));
}
}
This should return the route that matches the URL you specified, but I haven't actually tested this.
Note that if you want this new custom router to replace the built-in one, you will likely have to also create a new ServiceProvider to register your new class into the IoC container instead of the default one.
You could adapt the ServiceProvider in the code below to your needs:
https://github.com/jasonlewis/enhanced-router
Otherwise if you just want to manually instantiate your custom router in your code as needed, you'd have to do something like:
$myRouter = new MyRouter(new \Illuminate\Events\Dispatcher());
$route = $myRouter->resolveRouteFromUrl('/your/url/here');
It can be done without extending the default \Iluminate\Routing\Router class.
Route::dispatchToRoute(Request::create('/your/url/here'));
$route = Route::currentRouteName();
If you call Route::currentRouteName() after dispatchToRoute call, it will return current route name of dispatched request.
In Laravel, we can get route name from current URL via this:
Route::currentRouteName()
But, how can we get the route name from a specific given URL?
Thank you.
A very easy way to do it Laravel 5.2
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1'))->getName()
It outputs my Route name like this slug.posts.show
Update: For method like POST, PUT or DELETE you can do like this
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST'))->getName()//reference https://github.com/symfony/http-foundation/blob/master/Request.php#L309
Also when you run app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST')) this will return Illuminate\Routing\Route instance where you can call multiple useful public methods like getAction, getValidators etc. Check the source https://github.com/illuminate/routing/blob/master/Route.php for more details.
None of the solutions above worked for me.
This is the correct way to match a route with the URI:
$url = 'url-to-match/some-parameter';
$route = collect(\Route::getRoutes())->first(function($route) use($url){
return $route->matches(request()->create($url));
});
The other solutions perform bindings to the container and can screw up your routes...
I don't think this can be done with out-of-the-box Laravel. Also remember that not all routes in Laravel are named, so you probably want to retrieve the route object, not the route name.
One possible solution would be to extend the default \Iluminate\Routing\Router class and add a public method to your custom class that uses the protected Router::findRoute(Request $request) method.
A simplified example:
class MyRouter extends \Illuminate\Routing\Router {
public function resolveRouteFromUrl($url) {
return $this->findRoute(\Illuminate\Http\Request::create($url));
}
}
This should return the route that matches the URL you specified, but I haven't actually tested this.
Note that if you want this new custom router to replace the built-in one, you will likely have to also create a new ServiceProvider to register your new class into the IoC container instead of the default one.
You could adapt the ServiceProvider in the code below to your needs:
https://github.com/jasonlewis/enhanced-router
Otherwise if you just want to manually instantiate your custom router in your code as needed, you'd have to do something like:
$myRouter = new MyRouter(new \Illuminate\Events\Dispatcher());
$route = $myRouter->resolveRouteFromUrl('/your/url/here');
It can be done without extending the default \Iluminate\Routing\Router class.
Route::dispatchToRoute(Request::create('/your/url/here'));
$route = Route::currentRouteName();
If you call Route::currentRouteName() after dispatchToRoute call, it will return current route name of dispatched request.
I'm trying to learn Laravel, and I created controller (using artisan's php artisan controller:make AlbumController). Then, I added some functions there, mainly function parse:
/**
* Parse the album.
*
* #param int $id
* #return Response
*/
public function parse($id)
{
return 'http://api.deezer.com/'.$id;
}
In routes.php I added
Route::resource('album', 'AlbumController');
But when I try to access the parse page (http://localhost/album/parse/123) Laravel returns throw new NotFoundHttpException();.
What did I do wrong?
parse is not an included route in Laravel's resourse controller. Run php artisan routes to see your current route structure.
If you want to use the parse method in your controller you should define the route manually. Add something like
Route::get('album/parse/{id}', ['uses' => 'AlbumController#parse']);
to your routes file.
As an aside, the resource controller can be a handy way to get your CRUD routes up and running but it is good practice to define most of your routes explicitly as your routes.php file is useful documentation for your application and it makes the workings of it much easier to follow.
You need to change the route to
Route::get('album/parse/{id}', 'AlbumController#parse');
More of routing with parameters can you find HERE inside the Laravel Docs
And the docs with some information about Routing with Controllers
An little part of my route to give you an idea of how it could look:
Route::get('/partijen/nieuw', 'PartijenController#nieuw');
Route::post('/partijen/nieuw', 'PartijenController#save_new');
Route::get('/partijen/edit/{id}', 'PartijenController#edit');
Route::post('/partijen/edit/{id}', 'PartijenController#save_edit');
Laravel routing functionality allows you to name a resource and name a controller to go with it. I am new to Laravel and would like to know if anyone knows how to extend the resources method in the route class provided.
Basically say I have: (which works fine)
/invoices
But say I want:
/invoices/status/unpaid
How is this achievable?
To see the basics of what I am doing check:
http://laravel.com/docs/controllers#resource-controllers
Resource controllers tie you into a specific URLs, such as:
GET|POST /invoices
GET|PUT /invoices/{$id}
GET /invoices/create
and so on as documented.
Since, by convention, GET /invoices is used to list all invoices, you may want to add some filtering on that:
/invoices?status=unpaid - which you can then use in code
<?php
class InvoiceController extends BaseController {
public function index()
{
$status = Input::get('status');
// Continue with logic, pagination, etc
}
}
If you don't want to use filtering via a query string, in your case, you may be able to do something like:
// routes.php
Route::group(array('prefix' => 'invoice'), function()
{
Route::get('status/unpaid', 'InvoiceController#filter');
});
Route::resource('invoice', 'InvoiceController');
That might work as the order routes are created matter. The first route that matches will be the one used to fulfill the request.