To force HTTPS on a named route, the Laravel docs say do the following:
Route::get('foo', array('https', function()
{
return 'Must be over HTTPS';
}));
Now, on my first Laravel app, I have been using resource controllers. I don't think I will be using them for my second app, going on what I have since read, but for now they sit happily in my router.php file.
I wanted to force the back office part of my app to use HTTPS. So, my opening gambit was as follows:
Route::resource('backoffice', array('https','BackofficeController'));
Laravel didn't like the array.
So, instead I thought I would try putting at the next parameter:
Route::resource('backoffice', 'BackofficeController', 'https'));
But the next parameter needs to be an array. I could find no documentation on this, but I converted it to array. It still didn't work.
Route::resource('backoffice', 'BackofficeController', array('https')));
I even tried:
Route::resource('backoffice', 'BackofficeController', array('https'=>true)));
However, that failed too. So, how do I force a resource to use https?
Route::filter('forceHttps', function($req){
if (! Request::secure()) {
return Redirect::secure(Request::getRequestUri());
}
});
Route::group(['before' => 'forceHttps'], function(){
Route::resource('backoffice', 'BackofficeController');
});
Assuming you have a filter function like the one Andreyco suggested, which seems fine, you could do something similar to this:
//Andreyco's filter
Route::filter('forceHttps', function($req){
if (! Request::secure()) {
return Redirect::secure(Request::getRequestUri());
}
});
//backoffice group routing
Route::group(array('prefix' => 'backoffice', 'before' => 'forceHttps'), function()
{
Route::any('/', 'App\Controllers\BOindexController#index');
Route::resource('otherBackOfficeURI', 'App\Controllers\OtherBOController');
//other routes & controllers here...
});
This way, everything starting with site.tld/backoffice will go through the https filter (and most probably through a isAdmin filter) and then check inner function route rules. I think this will be more convenient.
Related
I have a single domain/subdomain project. In order to see the event by slug, I made this route:
Route::prefix('events')->namespace('Content\Controller')->group(function () {
Route::get('/', 'EventController#getIndex')->name('event.index');
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
Route::post('load-more-ajax/{region?}', 'EventController#postLoadMoreAjax');
Route::any('sorted-ajax/{region?}', 'EventController#anySortedAjax');
Route::get('category/{category_slug}/{subcategory_slug?}', 'EventController#getCategory');
});
After my page didn't load correctly, I did a dump in the controller:
public function getView($slug)
{
return $slug;
}
To get to the route I am using this URL: https://example.com/events/slug-example.
The problem is that the route is being hit as I see the response when I change it, but I am not getting the slug, instead I am getting Region object back.
If I do this:
public function getView($region, $slug)
{
return $slug;
}
Then I get the slug back. But I have no idea how is this possible, and how could I do it (I came as another dev on the existing project).
I tried commenting out all the middleware and it is still the same. How can I even make something fill the method if I didn't explicitly say it?
EDIT
I noticed there is binding going on in routes file:
Route::bind('region', function ($value) {
...
});
Now if I dd($value) I get the variable back. How is this value filled? From where could it be forwarded?
Looking quickly it should work, but maybe you was verifying other url.
Make sure you put:
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
routes at the end of routes you showed.
EDIT
If you think that's not the case and you don't have your routes cached you should run:
php artisan route:list
to verify your routes.
EDIT2
After explaining by OPs in comment, domain used for accessing site is:
{region}.example.com
So having $region in controller as 1st parameter is correct behaviour because of route model binding and other route parameters will be 2nd, 3rd and so on.
Instead of
Route::prefix('events')->namespace('Content\Controller')->group(function () {
Route::get('/', 'EventController#getIndex')->name('event.index');
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
Route::post('load-more-ajax/{region?}', 'EventController#postLoadMoreAjax');
Route::any('sorted-ajax/{region?}', 'EventController#anySortedAjax');
Route::get('category/{category_slug}/{subcategory_slug?}', 'EventController#getCategory');
});
try
Route::prefix('events')->namespace('Content\Controller')->group(function () {
Route::get('/', 'EventController#getIndex')->name('event.index');
Route::post('load-more-ajax/{region?}', 'EventController#postLoadMoreAjax');
Route::any('sorted-ajax/{region?}', 'EventController#anySortedAjax');
Route::get('category/{category_slug}/{subcategory_slug?}', 'EventController#getCategory');
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
});
I'm using Laravel 5.1 and am building a service that can be seen as JSON or HTML. This approach is already done by sites like reddit.
Example
Normal view: http://www.reddit.com/r/soccer
JSON view: http://www.reddit.com/r/soccer.json
As you can see, they simply add .json to an URL and the user is able to see the exact same content either as HTML or as JSON.
I now wanted to reproduce the same in Laravel, however I'm having multiple issues.
Approach 1 - Optional parameter
The first thing I tried was adding optional parameter to all my routes
Route::get('/{type?}', 'HomeController#index');
Route::get('pages/{type?}', 'PageController#index');
However, the problem I was facing here, is that all routes were caught by the HomeController, meaning /pages/?type=json as well as /pages?type=json were redirected to the HomeController.
Approach 2 - Route Grouping with Namespaces
Next I tried to add route groupings with namespaces, to seperate backend and frontend
Route::get('pages', 'PageController#index');
Route::group(['prefix' => 'json', 'namespace' => 'Backend'], function(){
Route::get('pages', 'PageController#index');
});
However, this doesn't work either. It does work, when using api as prefix, but what I want, is that I can add .json to every URL and get the results as json. How can I achieve that in Laravel?
You can apply regular expressions on your parameters to avoud such catch-all situation as you have for HomeController#index:
Route::get('/pages{type?}', 'PageController#index'->where('type', '\.json'));
This way it type will only match, if it is equal to .json.
Then, to access it in your controller:
class PageController {
public function index($type = null) {
dd($type);
}
}
and go to /pages.json
In a Laravel 4 app, i'm using subdomain routing around a bunch of Route::resource's like this:
Route::group(['domain' => '{account}.my.app'], function()
{
Route::group(['before' => 'auth'], function($account)
{
Route::resource('organisations', 'OrganisationsController');
Route::resource('clients', 'ClientsController');
Route::resource('domains', 'DomainsController');
});
});
In my auth filter i'm doing the following:
Route::filter('auth', function($route)
{
// you could now access $account in a controller if it was passed as an argument to the method
$account = $route->getParameter('account');
// share account variable with all views
View::share('account', $account);
// Auth::guest Returns true if the current user is not logged in (a guest).
if (Auth::guest()) return Redirect::guest('login');
});
Within my views I can now access $account, but if I want a call to URL::route() to be correct I have to manually pass the account variable, like URL::route('clients.show',['account' => $account]) otherwise it generates URLs like %7Baccount%7D.my.app.
This is a bit of a pain and doesn't seem that elegant, is there any other or better way to achieve this? I guess I could create my own route helper to use instead of the built-in one.
However, I also do redirects with Redirect::route() within controllers so I would also need to make updates here.
EDIT
As suggested in the comments it may be that extending the Route API is the best approach here. Does anyone have any suggestions how this should be done?
Thanks.
Following this http://laravel.com/docs/quick#routing
I add this:
Route::get('users', function()
{
return 'Users!';
});
to the bottom of /app/routes.php and GET it from my browser http://localhost/users. But the returned result is users Not Found.
I've also tried a route of /users too, and this does the same.
Oh no, the route should be:
http://localhost/index.php/users
That should work.
I have just started tinkering with Laravel (PHP newbie alert) and I have a doubt on how to implement my REST JSON APIs on this framework.
The desired URL path should be:
http://api.mysite.com/APIKEY/FUNCTION/(ARGUMENTS)*
But what is the best way to do it?
I did not find any enough explanatory guide, because it is assumed that each feature (authentication, search, and so on) are on different routes.
At the moment I managed to create migrations and models for the needed data and I also set a route this way:
Route::get('/{apikey}/{function}/{arg1}/{arg2}/{arg3?}',
//The first two arguments are mandatory, the 3rd optional
function($apikey,$function,$arg1,$arg2)
{
return Response::json(array(
'status'=>'200'),
200);
})
->where(array('function'=>'[A-Za-z]+'));
This should be the correct action flow, but I have some doubts.
Check that apikey is valid, if not return a 404 json response. How do I call such function, where do I define it?
If key check is successful, understand which function is needed (should I use a switch construct or is there a better way to implement this, like a route group? In all examples with Route::group there is a static prefix, but here the prefix is apikey, a variable)
Return data - if available - getting it from the database. I suppose that for each function i should code a specific controller that gets data from the database using the Models.
#1. I think I'd probably use a route filter for this, like so:
Route::filter('apikey', function(){
if (Shared\API::checkIfKeyIsValid(Input::get('key') != true){
return Shared\Errors::handleError("bad-api-key");
}
});
You can see this filter checks to make sure some session variables are set and match, and if it returns ANYTHING, that's failing, and it won't send the user where the route normally goes. You'd call it in the route like so:
Route::get('play/{id}', array('before' => 'loggedin', 'uses' => 'ThingController#doThing'));
#2. I think a route group is how I'd structure this (if I understand what you're asking).
Edit: You've changed the question since I answered, regarding the prefix being a variable. I'd reorder your arguments so the API key is at the end, or you could take a look at this, which might do what you want: https://github.com/jasonlewis/enhanced-router
Route::group(array('prefix' => 'api'), function()
{
//the routes for all API calls
Route::group(array('prefix' => '/v1'), function()
{
//for version 1
Route::group(array('prefix' => '/thing', 'before' => 'loggedin'), function()
{
//for things only
Route::get('/getThing/{id}', 'APIController#getThing');
Route::get('/getDifferentThing/{id}/{aux}/{optional?}', 'APIController#getDifferentThing');
});
});
});
#3. The returning of the data should be done via your controller with the data coming from the model. Either return it as a view, or just return it as JSON like so:
return Response::json($data);