I'm building an API for user and admin.
Got stuck at edit user profile routing.
on admin route i use Route::resource('user', 'UserController')
on user route i use Route::get('profile', 'UserController#show')
At the show method Laravel default has
public function show($id)
{
}
the different between them is on admin I can use /id but on user i check their token from middleware and merge the request to get their user_id so there is no need for the API to use profile/{id}.
The question is how can I use the same method but there is an argument to fill and the route still /profile?
One of my solution is :
public function show($id){
if ($request->has('user_id')):
$id = $request->query('user_id');
endif;
}
It working but when i read the code, it's really redundant always checking it and replace the id.
Just place the request object as a parameter in your controller and get the input from the request object when you use your user route.
Thanks
Related
I am working on a school project. while working on a schools detail page I am facing an issue with the URL. My client needs a clean URL to run AdWords. My school detail page URL: http://edlooker.com/schools/detail/4/Shiksha-Juniors-Ganapathy. But he needs it like http://edlooker.com/Shiksha-Juniors-Ganapathy. If anyone helps me out it will be helpful, thanks in advance.
You need to define this route after all routes in your web.php (if laravel 5.x) or in routes.php (if it is laravel 4.2).
Route::get('{school}','YourController#getIndex');
And your controller should be having getIndex method like this,
public function getIndex($school_name)
{
print_r($school_name);die; // This is just to print on page,
//otherwise you can write your logic or code to fetch school data and pass the data array to view from here.
}
This way, you don't need to use the database to get URL based on the URL segment and you can directly check for the school name in the database and after fetching the data from DB, you can pass it to the school details view. And it will serve your purpose.
Check Route Model Binding section in docs.
Customizing The Key Name
If you would like model binding to use a database column other than id when retrieving a given model class, you may override the getRouteKeyName method on the Eloquent model:
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'slug';
}
In this case, you will have to use one front controller for all requests and get data by slugs, for example:
public function show($slug)
{
$page = Page::where('slug', $slug)->first();
....
}
Your route could look like this:
Route::get('{slug}', 'FrontController#show');
Assume the following routes in a Laravel 5.5 API:
// custom routes for THIS user (the user making the request)
Route::get('/user', 'UserController#show');
Route::get('/user/edit', 'UserController#edit');
// register CRUDdy resource routes for users
Route::resource('users', 'UserController');
Let's use edit as the example:
public function edit(User $user)
{
...
}
As you can see, the edit route contains a type-hinted $user parameter. This works just fine for the users/13/edit route, as expected. However, I'd to configure the route /user/edit to pass along the $request->user() user object to the function. I don't want to check for the user object in the actual edit method as that could interfere with other validation (for instance, I don't want to default to the current user if someone passes a non-existent user ID, I want to return an error in that case).
In short: how can I register a route to first create a parameter, then pass it to the given controller method? My first thought was to use a closure:
Route::get('/user/edit', function(Request $request){
$user = $request->user();
});
But once inside the closure, I'm not certain how to then carry the request forward to the appropriate controller method.
Instead of a closure, you could make a new controller method that calls edit with the current user.
Let's say your route is this:
Route::get('/user/edit', 'UserController#editSelf');
Then in your controller:
public function editSelf(Request $request)
{
$this->edit($request->user());
}
I'm trying to make a "Profile settings" section in an application.
The thing is, I learned how to do this the "Admin" way, the route would be /users/{user}/edit, the would call the edit method on the controller and it would return the edit view. There I would have a form which the user would patch to the route users/{user} and it would call the update method on the controller.
But I don't want anyone editing other users, so I'd like to know if there's a way to limit this route to the current user only.
Thanks in advance.
Since version 5.1 Laravel has Policies which are exactly what you need.
You can create a new policy by typing in command:
php artisan make:policy UserPolicy
In your UserPolicy class you can include the following method:
public function updateProfile(User $user, User $updatedUser) {
return $user->id === $updatedUser->id;
}
Please note: The first parameter $user is resolved automatically behind the scenes and is the currently logged in user. When checking the policy through the Gate facade in your application you need to pass only the second parameter $updatedUser.
Then you need to register your policy in the AuthServiceProvider:
use Acme\User;
use Acme\Policies\UserPolicy;
...
class AuthServiceProvider extends ServiceProvider {
protected $policies = [
User::class => UserPolicy::class
]
Now when you have your policy registered you can check it across your app using the Gate facade like so:
if(Gate::allows('updateProfile', $user)) {
// Your logic goes here
}
Or the other approach with I like more using the denies method and include it at the beginning of my controller methods and return http error:
public function edit($id) {
if(Gate::denies('updateProfile', $user)) {
abort(403, 'You do not have permissions to access this page!');
}
// The check is passed and your can include your logic
}
You can also check for permissions in your blade files using can and cannot like so:
#can('updateProfile', $user)
// Show something only to the user that can edit the $user's profile
#endcan
For more info check the docs.
you should not need to pass in the user id as there user is already logged in and there for should be able to edit themselves, thus only targetting the logged in user.
So you can use the routes /user/editand /user/updateetc
Just get the current user details like
Auth::user()->id
or something else like
$user = Auth::user();
Thus only the logged in user (themselves) can be edited.
In the view there should be a button or link, on click pass the ID to the desired route that's it.
Example:
For Grabbing the current logged in User id you should do like
$user = Auth::user()->id;
And directly in the route you can get it like
Edit
Now when someone clicks on the Edit Button/Link, the route will look like route/currentuserid.
I am using Laravel 5.1 for my project. I am trying to secure Routes and make sure only logged in user can access certain routes. I am aware about middlewares but I am wondering if anyone post an example or a link explaining about middleware and how to protect a page using middleware.
Thanks
To build on the answer given by Joe Rose, you can also specify the middleware in your controller rather than in your routes.php file.
E.g you could have your routes set out like
Route::get('/example', 'ExampleController#index');
Route::post('/example/post', 'ExampleController#post');
Route::resource('blog', 'BlogController');
And then inside your controller reference it like so:
class ExampleController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
//....
If you're looking for more info, check out the link to the docs Joe gave, and also this blog post which explains what middleware is really well and how to create your own if you need to.
You are correct about using middleware. The included Auth middleware is what you should use, as long as you are also using the included Auth controller to authenticate users. You would write your route like this:
Route::get('/page', array(
'uses' => 'Controller#method',
'middleware'=>'auth'
));
(The above example is using a GET request, but it could other request types, like POST for example).
This will use the default behavior of the middleware which checks to see if the user is logged in (authenticated). You can also extend or overwrite the built-in functions to allow you to direct the application on where to send the user if they are or are not logged in, etc. Laravel's official documentation is a good starting point: link
I have a fairly simple ACL system set up. The filter checks if the user is part of a user group which has access to the route or if the user has access to the route. It works for individual routes and works for resources in general. However I want some users to have access to a specific method of a resource route, but not all of it. for example, user1 is part of the admin group and always has access to the admin resource route but user2 is not a part of the admin user group and I want to give him access to teh resource admin/create. How can I go about this in Laravel 4 with my setup
Database
Routes:
id
route
created_by
last_editted_by
created
updated
deleted_at
acl (table it looks at to see if user has access)
id
routes_id
user_id
group_id
created
updated
deleted_at
Filter
if (Auth::check()){
$route = Request::segment(1);
$user_id = Auth::user()->id;
$acl_count = Acls::join('routes','routes.id','=','acl.routes_id')
->where('routes.route','=',$route)
->Where(function($in_parenthesis) use($user_id){
$in_parenthesis->whereIn('acl.group_id',function($where_in) use($user_id){
$where_in->select('group_id')
->from('user_group_junction')
->where('user_id','=',$user_id);
})
->orWhere('acl.user_id','=',$user_id);
})
->count();
if($acl_count < 1){
return Redirect::to('/');
}
}else{
return Redirect::to('/');
}
Routes
Route::get('/','HomeController#index');
Route::get('login','AuthorizationController#loginForm');
Route::post('authenticate','HomeController#authenticate');
Route::get('logout','HomeController#logout');
Route::group(array('before'=>'auth'),function(){
Route::group(array('before'=>'user_permission'),function(){
Route::get('protected','HomeController#protectedPage');
Route::resource('sources', 'SourcesController');
Route::resource('admins', 'AdminsController');
});
});
You can use beforeFilter inside the __construct method of the AdminBaseController like this (create a different one for admin controllers only)
class AdminController extends AdminBaseController {
function __construct() {
// Use filter on all methods but not on create
$this->beforeFilter('admin', array('except' => array('create')));
}
}
Also, you may directly use this beforeFilter inside your resource controller and use except or you can use only (only works reverse of except, allows access to all but filters only mentioned methods in the array). You can also check conditions inside the constructor method s well.
I figured out that part of my problem is with the filter. I am only looking at the first segment of the url which doesn't work correctly if my route (whether it is a resource or just a route with a "/" in it) won't work. Thus I asked another question located here