I am trying to test the routing mechanism of my app (which is a Laravel PHP App) that was based on the documentation (http://laravel.com/docs/routing#route-prefixing). The case is: We are trying to handle the app localisation based on the route, for example:
www.example.com/en/something -> Should use EN as language,
www.example.com/es/something -> Should use ES as language,
www.example.com/de/something -> Should use DE as language.
We accomplished the behaviour described before by using prefixes and it works perfect. The thing is that I am not able to write tests to test this behaviour. I did a little bit of research, and I found this third party library (https://github.com/mcamara/laravel-localization/blob/master/tests/LocalizerTests.php), that uses a similar approach, and I think it might help you understand which is the situation.
If you take a look in there, he is not testing the scenario that I want to test (I mean, with the locale code on the path).Btw: I've already turned on the filters with Route::enableFilters() and it does not work :(
Thanks a lot
If you use route inside the group.
Route::group(array('domain' => {account}.'.$domain), function()
{
Route::get('myproduct/en/list', 'HomeController#showWelcome');
});
then try this.
public function testBasicExample() {
$crawler = $this->client->request('GET', 'http://subdomain.domain.local/myproduct/en/list');
$this->assertTrue($this->client->getResponse()->isOk());
}
Related
I've built a multilanguage app in Laravel 5.3 and I have a bunch of api routes that return me some resources where the url is something like this http://app-domain.com/api/resource when I'm on my default language.
The problem presents itself when I'm not in the default language. When the app tries to call the api it sends a request to http://app-domain.com/locale/api/resource which returns nothing since it's not the correct path.
My implementation is very simple, just basic routing in my routes/api.php
Route::group([
'prefix' => 'api'
],function() {
Route::get('resource', 'ApiController#getResource')->name('get-resource');
});
Then I'm using jquery ajax object to call it
$.get( "api/resource", function( data ) {
//run somecode
});
How can I address this problem and have my api routes resolving correctly no matter the language? Is there some params that I can set in the routes to prevent this? I've been looking in the documentation but found nothing relevant.
P.S.: I'm using Mcmanamara Laravel Localization
IMHO for setting locale its better if you use a query-string: i.e.:
http://app-domain.com/api/resource?locale=en
For two, valid, reasons:
1) The locale in the querystring could also be non existing, so you can fallback to default locale.
2) Having a locale parameter in a route could conflict with other routes parameters generating a lot of confusion
I am working on a REST API project using Slim 3, and I was wondering if there is an easy way to implement the following routing without creating separate routes for the shorthands.
The shorthand is ../me for ../users/{id} where the id is the current users ID.
So far its easy, I just create the two routes, and map them to the same controller method; but there are many more endpoints which use the same logic for example:
../users/{id}/posts should use the same as ../me/posts,
../users/{id}/groups/{gid} should use the as ../me/groups/{gid}, etc.
I used the double dots to indicate that there are preceding URI parts (version, language etc.).
I hope you get the idea now.
So my question is this: is there a way to reroute these kind of requests, or maybe is there a route pattern that would fit my needs and i missed it, maybe even I have to fiddle in a middleware to achieve this?
Thanks
There is a way to take advantage of Slim's FastRoute router. Put a regular expression into the variable part of your route and do the extra parsing inside the controller:
$app->get('/whatever/{id:users/\d+|me}', function ($request, $response, $args) {
if (preg_match('%^users/(\d+)$%', $args['id'], $parsed)) {
// This is /users/{id} route:
$user = $parsed[1];
} else {
// This is /me route:
$user = 'automagically recognized user';
}
return $response->withStatus(200)->write('Hello '.$user);
});
However I'd find that strange and would recommend mapping the same controller to two individual routes, as you do now. Two reasons come to my mind:
You can put the user ID lookup for 'me' route only into the one where it's needed (by having another controller adding this logic on top of the main one).
It's easier to comprehend for other developers on the team.
Hope it helps!
Try it
$app->get('/users[/{id}/groups[/{msgid}]]', function ($request, $response, $args) {
}
and see the oficial documentation in http://www.slimframework.com/docs/objects/router.html
I am trying to use Symfony to replicate behavior in an existing Framework (zikula). This framework is extensible using modules which are basically extended symphony bundles. The old framework had urls like so
index.php?module=foo&type=bar&func=zip
which in symfony speak roughly translates to
index.php?bundle=foo&controller=bar&method=zip
The framework has an AbstractController which has a magic method like:
public function __call($method, $args)
{
$event = new \Zikula\Core\Event\GenericEvent($this, array('method' => $method, 'args' => $args));
$this->eventManager->dispatch('controller.method_not_found', $event);
if ($event->isPropagationStopped()) {
return $event->getData();
}
}
so, if you created a url with a method that didn't exist in the bundle, you could create a listener to capture it and send a response that looks like and behaves like it came from the specified bundle. We use this to call module services that are available to all modules and provided in a separate module but look like they are served by the 'host' module.
Now I am trying to replicates this using symfony and routing.
the first problem is generating a route that doesn't technically exist. Is this possible?
The second problem is capturing the RouteNotFoundException (which I know how to do, we already have listeners for other exceptions).
The last problem is making it appear that the bundle is serving up the response when it is actually being served by an event listener (or something else). This last part is important because other content in the response needs to come from the module/bundle.
I have tried changing the current listener to a controller, and also tried adding a method to our extension of symfony's AbstractController, but haven't yet achieved what I am hoping to achieve. I'm hoping for some suggestions on new ideas or methods to try.
I gave up trying to replicate the exact behavior as it seems impossible (it is also pretty difficult to describe). So I have resorted to a normal controller with standard route, but I found a way to make it appear to belong to the original 'host' module. Thanks to Gerry, ggioffreda and DerStoffel for offering ideas.
I'm using Slim. In the documentation they only show examples working with only one index.php file, which has really little functionality for every route. For example:
$app = new \Slim\Slim();
$app->get('/books/:id', function ($id) {
//Show book identified by $id
});
But in my case, my index.php file is getting bigger and bigger, now I have a lot of code for most routes, what is the best practice in this case? to include files inside the routes closures? What happens with the scope of global variables, like DB connection or app config? Thank you
Brian Nesbitt made a nice post about this: http://nesbot.com/2012/11/5/lazy-loading-slim-controllers-using-pimple.
If you don't want to use pimple, than you can get some idea from the section "Common first attempt", on how to separate you files.
update:
Since version 2.4.0 you can use the inbuilt "Class controller": Version 2.4.0
I'm working in a RESTFul API with laravel, and I want to use content negotiation in my project, but I don't know how to accomplish that.
I have my controllers separted by api version, and I want to distinguish between api versions and use the correct controllerdepending on the version.
My API router is:
Route::group(array('prefix' => 'api'), function() {
Route::resource('users', 'API\V1\UsersController');
});
Should I create a api.type filter to use in my route group or Should I do that in the route group clousure or maybe, in each controller?
Don't be afraid to branch out your application logic into library classes. You don't have to fit everything inside of Laravel's given folder structure.
In fact, adding in your own namespaced group of classes can have a big benefit. You can see some setup on creating your own application library here.
Once you have that set up, you can create a class whose responsibility is to decide what content type to return. This might be based on an Accept header, URL parameter or whatever you define (That's up to you, the API creator).
Perhaps this class will take the Accept header and normalize it to something like "json", "xml" and "html".
The Request class has some methods to help you if you do it via the Accept header.
So, in pseudo code (syntax errors to follow!), your controller might do something like this:
/* GET /api/users */
public function index()
{
// Might return "json" or "xml" or "html"
$contentType = \My\ContentType\Class->getContentType();
$users = User::all();
// Not shown here is logic to set `content-type` header in the returned response (json vs xml vs html)
// Perhaps a method to go into your implementation of \My\ContentType\Class
return View::make('users.'.$contentType)->with(array( 'users' => $users ));
}
That's just an idea of what you might do. The key point is to get yourself working in a library that you can put business logic into to get you started with an idea of how to accomplish adding in business logic for your application.
Hope that helps.