Let's assume I have different users that have the access to some pages. Pages are almost the same, but with minor changes, like delete button is not shown for user but for the admin.. and so.
If I have a controller called DashboardController which has a method index that shows some info related to the type of the user.
I have two approaches, one is to make different controllers like:
Admin\DashboardController
User\DashboardController
but my routes will be like : localhost/admin/dashboard and localhost/user/dashboard
and the other approach is to make one controller called DashboardController and check for the type of the user there.
So which approach is better, and is there a better approach to make one URL instead of prefixing them?
I suggest taking a look at view composers: http://laravel.com/docs/4.2/responses#view-composers
View composers make it possible to bind extra logic to a view. This could remove some double code or in your case could validate the authenticated user and bind a boolean to the view.
Quick example:
// DashboardComposer.php
class DashboardComposer {
public function compose($view)
{
$user = Auth::user();
$isAdmin = $user->admin; // The attribute 'admin' would be a boolean.
$view->with(
'showDelete',
$isAdmin
);
}
}
In your blade view you would check for this state:
// dashboard.blade.php
#if($isAdmin)
<button>Delete</button>
#endif
Please take note that this does NOT protect your 'delete' endpoint!
Adding a before filter on these routes should suffice.
// routes.php
Route::delete('resource', [
'as' => 'resource.delete',
'uses' => 'DashboardController#delete',
'before' => 'admin' // This would call a custom filter.
]);
And lastly the custom filter would almost look the same as the view composer.
// filters.php
Route::filter('admin', function () {
$user = Auth::user();
return $user->admin; // The attribute 'admin' would be a boolean.
});
One last note I've placed the view composer in a separate class, by doing so I can better organise my code. The filter is placed in the same file as all the other filters, however it is possible to do the same as with the composer: http://laravel.com/docs/4.2/routing#route-filters
Take a look at 'Filter Classes'.
I have solved this like the following way
routes.php
Route::get('dashboard', ['middleware' => 'auth', 'uses' => 'DashboardController#index']);
// Admin
Route::group([ 'middleware' => 'toegang:admin' ], function ()
{
Route::get('dashboard/projecten', 'ProjectController#index');
Route::get('dashboard/groepen', 'GroepController#index');
Route::get('dashboard/periode', 'PeriodeController#index');
Route::get('dashboard/producten', 'ProductController#index');
Route::get('dashboard/gebruikers', 'UserController#index');
Route::get('dashboard/scoring_rubrics', 'ScroingRubricsController#index');
Route::get('dashboard/pos', 'PosController#index');
Route::get('dashboard/project_status', 'ProjectStatusController#index');
Route::get('dashboard/beoordeling', 'BeoordelingController#index');
});
// Student
Route::group([ 'middleware' => 'toegang:student' ], function ()
{
Route::get('dashboard/project_status_student', 'ProjectStatusStudentController#index');
Route::get('dashboard/account', 'AccountStudentController#index');
});
I have multiple roles admin / student and they uses one controller DashBoardController.
SO to access dashboard both admin or student must be auth to access the dashboard homepage. For the specific pages for admin and student i use two route groups.
dashboardcontroller#index
class DashboardController extends Controller
{
/**
* Display a listing of the resource.
*
* #return View View
*/
public function index()
{
$autorisatie = Auth::user()->autorisatie();
return view('dashboard.home', compact('autorisatie'));
}
In the dashboard controller i will get role from the user by calling autorisatie()
autorisatie method in user model
public function autorisatie($rol = null)
{
$autorisatie = DB::table('autorisatie')
->select('rol')
->where('autorisatieID', Auth::user()->autorisatieID)
->first();
// Check als de opgegeven role in de routes hetzelfde is
// Als de ingelogde user
if($rol)
{
// Return true als $autorisatie rol hetzelfde is als de
// opgegeven route role
return $autorisatie->rol == $rol;
}
// return false
return $autorisatie->rol;
}
And in my view i will check for different displaying data or pages like so:
view dashboard
{{--Extends master page--}}#extends("master.master")
{{--Section for content area--}}
#section("content")
<h1>Dashboard</h1>
<p>
Dashboard - {{$autorisatie}} <br>
#if ($autorisatie == 'admin')
Show admin things.....
#elseif ($autorisatie == 'student')
Show student things...
#endif
</p>
Related
I have this route declared on laravel:
Route::get('pages/{page}/{slug}', 'Common\Pages\CustomPageController#show')
->middleware(['web', 'prerenderIfCrawler']);
This route works fine and works if you make requests to:
https://example.com/pages/1/test-page
https://example.com/pages/2/other-page
https://example.com/pages/3/url-test
The problem is that I need a more friendly url as well as.
https://example.com/test-page
https://example.com/other-page
https://example.com/url-test
I want remove the suffix called pages, The numbers for the pages will never change and will be static for each one.
I've tried to make static routes for each one but can't get it to work.
Route::get('other-page', array('as' => 'other-page', function() {
return App::make('Common\Pages\CustomPageController')->show(2);
}))->middleware(['web', 'prerenderIfCrawler']);
I would appreciate a little help.
You could always get the URL segment in the Controller and use that to know what page you are on. If you don't want to do that you could pass extra information in the 'action' to specify the page:
Route::middleware(['web', 'prerenderIfCrawler'])->group(function () {
Route::get('test-page', [
'uses' => 'Common\Pages\CustomPageController#show',
'page' => 'test-page',
]);
...
});
Then you can get this extra information in the Controller:
public function show(Request $request)
{
$page = $request->route()->getAction('page');
...
}
If you knew all the pages you can use a route parameter with a regex constraint to restrict it to only those page names:
Route::get('{page:slug}', ...)->where('page', 'test-page|other-page|...');
public function show(Page $page)
{
...
}
You could just make use of a wildcard to catch your routes like this:
Route::get('/{slug}', 'Common\Pages\CustomPageController#show')
->middleware(['web', 'prerenderIfCrawler']);
Then in your controller:
public function show($slug)
{
$page = Page::where('slug', $slug)->first();
// ...
}
Just be careful with where you place the route. It should be at the end of your routes otherwise it will catch all the request of your app.
// ...
// my other routes
// ...
Route::get('/{slug}', ...);
By the way, if you want to bind your page models using the slug attribute do this:
Route::get('/{page:slug}', 'Common\Pages\CustomPageController#show')->//...
^^^^^^^^^
Then in your controller:
public function show(Page $page)
{ ^^^^^^^^^^
// ...
}
Check this section of the docs.
I want that when the user click the profile page i want to pass Auth::user()->username as argument to my userController's show method.I have the profile link as following:
<li>Profile</li>
And in my route i have the following route
Route::get('/profile/{username}',function(){
return View::make('user.show')->with($username);
});
my question is how i can set username in my '/profile/{username}' as Auth::user()->username when i click the profile link?currently the profile link does not attach any parameter with it
First of all
{{URL::to('/profile')}} is not pointing to Route::get('/profile/{username}) url,there are two different routes
So what you need to do is either change the link , i.e.
{{URL::to('/profile/' . \Auth::user()->username)}}
and then in your route file
Route::get('/profile/{username}',function($username){
return View::make('user.show')->with(['username' => $username]);
});
//note that you need to pass the array in with() method
or you can do this
Route::get('/profile/{username}',function($username){
return View::make('user.show',compact('username'));
});
When the user clicks on profile link:
<li>
My Profile
</li>
The UserController#show method is called.
<?php
// routes.php
Route::get('profile/{username}', 'UserController#show')->name('user.show');
// UserController.php
public function show($username)
{
$user = User::whereUsername($username)->first();
return view('user.show', compact('user'));
}
and a View response is returned to the user.
#update
If you need is just redirect the control to the UserController#show method, you can do this:
<li>
My Profile
</li>
<?php
// routes.php
Route::get('profile/{username}', function ($username) {
return redirect()->route('user.show', Auth::id());
})->name('user.profile');
Now if you want customize the UserController#show action:
<li>
My Profile
</li>
The UserController#show method is called.
<?php
// routes.php
Route::resource('user', 'UserController', ['except' => ['show']);
Route::get('profile/{username}', 'UserController#profile')->name('user.profile');
Now you can delete the UserController#show method if you want or change the profile method name to show.
// UserController.php
public function profile($username)
{
$user = User::whereUsername($username)->first();
return view('user.show', compact('user'));
}
A quick way is to setup a redirect from /profile and it won't break the functionality if they want to view someone else's profile.
Route::get('/profile',function(){
return Redirect::to('/profile/'.Auth::user()->username);
}
However, I'd recommend doing an Auth::check() before the redirect.
i did something like the following
<li>Profile</li>
and in route.php:
Route::get('/profile',function(){
return redirect()->route('user.show',[Auth::user()->username]);
});
I am using Hashid to hide the id of a resource in Laravel 5.
Here is the route bind in the routes file:
Route::bind('schedule', function($value, $route)
{
$hashids = new Hashids\Hashids(env('APP_KEY'),8);
if( isset($hashids->decode($value)[0]) )
{
$id = $hashids->decode($value)[0];
return App\Schedule::findOrFail($id);
}
App::abort(404);
});
And in the model:
public function getRouteKey()
{
$hashids = new \Hashids\Hashids(env('APP_KEY'),8);
return $hashids->encode($this->getKey());
}
Now this works fine the resource displays perfectly and the ID is hashed.
BUT when I go to my create route, it 404's - if I remove App::abort(404) the create route goes to the resource 'show' view without any data...
Here is the Create route:
Route::get('schedules/create', [
'uses' => 'SchedulesController#create',
'as' => 'schedules.create'
]);
The Show route:
Route::get('schedules/{schedule}', [
'uses' => 'Schedules Controller#show',
'as' => 'schedules.show'
]);
I am also binding the model to the route:
Route::model('schedule', 'App\Schedule');
Any ideas why my create view is not showing correctly? The index view displays fine.
Turns out to solve this, I had to rearrange my crud routes.
Create needed to come before the Show route...
There's a package that does exactly what you want to do: https://github.com/balping/laravel-hashslug
Also note, that it's not a good idea to use APP_KEY as salt because it can be exposed.
Using the above package all you need to do is add a trait and typehint in controller:
class Post extends Model {
use HasHashSlug;
}
// routes/web.php
Route::resource('/posts', 'PostController');
// app/Http/Controllers/PostController.php
public function show(Post $post){
return view('post.show', compact('post'));
}
Is it possible to access route parameters within a filter?
e.g. I want to access the $agencyId parameter:
Route::group(array('prefix' => 'agency'), function()
{
# Agency Dashboard
Route::get('{agencyId}', array('as' => 'agency', 'uses' => 'Controllers\Agency\DashboardController#getIndex'));
});
I want to access this $agencyId parameter within my filter:
Route::filter('agency-auth', function()
{
// Check if the user is logged in
if ( ! Sentry::check())
{
// Store the current uri in the session
Session::put('loginRedirect', Request::url());
// Redirect to the login page
return Redirect::route('signin');
}
// this clearly does not work..? how do i do this?
$agencyId = Input::get('agencyId');
$agency = Sentry::getGroupProvider()->findById($agencyId);
// Check if the user has access to the admin page
if ( ! Sentry::getUser()->inGroup($agency))
{
// Show the insufficient permissions page
return App::abort(403);
}
});
Just for reference i call this filter in my controller as such:
class AgencyController extends AuthorizedController {
/**
* Initializer.
*
* #return void
*/
public function __construct()
{
// Apply the admin auth filter
$this->beforeFilter('agency-auth');
}
...
Input::get can only retrieve GET or POST (and so on) arguments.
To get route parameters, you have to grab Route object in your filter, like this :
Route::filter('agency-auth', function($route) { ... });
And get parameters (in your filter) :
$route->getParameter('agencyId');
(just for fun)
In your route
Route::get('{agencyId}', array('as' => 'agency', 'uses' => 'Controllers\Agency\DashboardController#getIndex'));
you can use in the parameters array 'before' => 'YOUR_FILTER' instead of detailing it in your constructor.
The method name has changed in Laravel 4.1 to parameter. For example, in a RESTful controller:
$this->beforeFilter(function($route, $request) {
$userId = $route->parameter('users');
});
Another option is to retrieve the parameter through the Route facade, which is handy when you are outside of a route:
$id = Route::input('id');
What I basically want is user permissions.
I've got an table called 'accounts' in my database. There is a column called 'group_id'.
I want to set it when the 'group_id' = 3, then the user is admin. Then he can view special sites, buttons, and things like that. I've tried to implement something like that:
public function ($roleName) {
$role = $this->roles;
if ($role->name == $roleName) {
return true;
}
return false;
}
Also, I don't know what and how the model is needed, do I need an new one and things like that.
Old post, but maybe someone will find this useful
Add a method to your User model that returns true if the user is an admin. In our case here, it's simply "is our group_id equal to 3?"
// models/User.php
class User extends Eloquent
{
...
public function isAdmin()
{
return $this->group_id == 3;
}
}
Next add a filter that can be used to protect routes
// filters.php
Route::filter('admin', function($route, $request)
{
if ( ! Auth::user()->isAdmin())
{
return App::abort(401, 'You are not authorized.');
}
});
Finally use the filter to protect a group of routes. I this simplified case, only an admin user could access /admin
// routes.php
Route::group(array('before' => array('auth|admin')), function()
{
Route::get('/admin', function()
{
return Response::make("You're an admin!");
}
});
Based on this post:
http://laravelsnippets.com/snippets/admin-route-filter
I suggest Authority for Laravel 4
I personally use Verify package for user management.