Cannot access resource id from route in Laravel 5 delete request? - php

I am trying to authorize a delete request on a resource if the resource belongs to a user for which I have created a Delete Request in Laravel 5.
For another resource I could do something like:
public function authorize()
{
if(Pivot::findOrFail($this->route('pivots'))->user_id != Auth::user()->id){
return false;
}
return true;
}
So basically $this->route('pivots') would return the id of the pivot that the user is trying to delete and I would check if it belongs to the current user.
But now I am trying for another resource similar to this one:
public function authorize()
{
if(CropSection::findOrFail($this->route('crop-sections'))->pivot->user_id != Auth::user()->id){
return false;
}
return true;
}
I tried to die and dump $this->route('crop-sections') and it comes out to be null but the request was http://localhost:8000/crop-sections/10 which has the id as 10.
What am I doing wrong?

You have to change 'crop-sections' to 'crop_sections'.
Route parameters cannot contain the - character. Use an underscore (_) instead.
You can find more info here.

Related

Laravel User Policy Is Returning The Authenticated User's Information And Not The External User

I created a Laravel policy called "UserPolicy" which is supposed to filter out users that do not have the permission to edit, delete, and update other users. The problem is that I am trying to pass an external user's information to the policy. But instead, it just returns the authenticated users information.
My Policy:
public function edit(?User $user)
{
if(auth()->check()) {
dd($user);
$userpower = auth()->user()->roles()->min('power');
if($userpower <= $user->power) {
return true;
} else {
return false;
}
} else {
return false;
}
}
My Controller:
public function edit(User $user)
{
$this->authorize('edit', $user);
$roles = Role::all();
$user = User::where('steamid', $user->steamid)->with('roles')->first();
return view('manage.includes.users.edit')->with(compact('user', 'roles'));
}
For example, I am the user Bob. I am trying to edit the user, John. As a test, I included the dd() function to dump the $user information that is passing into the Policy. After seeing the results, instead of John's information being passed, it is Bob's. How can I make it where it is John's information and not Bob's.
Thank you for your help, if you need more information please let me know.
The first parameter is the authenticated user. The second parameter is the resource. Try defining your policy as:
/**
* Can a guest user, or an authenticated user (let's call this first user Bob)
* edit another user (let's call that second user John) ?
*/
public function edit(?User $bob, User $john)
{
//
}

How to treat 'No query results for model' in Laravel

We have a DB with 100 users.. for example
And here is the route
Route::get('/users/{user}/edit', 'UserController#edit');
Here is the method
public function edit(User $user)
{
$hi = 'Hello';
return $hi;
}
Ok.. if I do something like this
http://localhost/users/99/edit | WORKS
http://localhost/users/100/edit | WORKS
http://localhost/users/101/edit | PROBLEM
How to solve when the user change the value from URL with an inexistent record..?
In this case I would pass the user id as a parameter rather than explicit binding:
Route::get('/users/{userId}/edit', 'UserController#edit');
When a model is not found you will get a ModelNotFoundException exception thrown, you can catch it and treat this case
Controller:
use Illuminate/Database/Eloquent/ModelNotFoundException;
[...]
public function edit($userId)
{
try{
$user = User::find($userId);
//do some stuff
} catch (ModelNotFoundException $e){
//treat error (log the activity, redirect to a certain page)
//or display a 404 page
//dealer's choice
}
}
In your case the user can't be found, which is a 404:
public function edit(User $user)
{
$user = false; // dummy/example
if ($user) {
return $your_results;
} else {
return view('errors.404');
// assuming you have a folder called 'errors' inside your 'views' folder
// and the file name is `404.blade.php`
// and are using blade files.
}
}
If the user can be found, show whatever you need to, else, show a 404 blade view.
A little late, but it is an useful question.
To suppress the error message you can set the debug mode in the (dot)ENV file to false APP_DEBUG=true. Due to the route model binding, the other solutions above won't help you, because if the model is not found, you won't get into the controller. Unless you don't get the model but only the id or slug etc. and then make a query against the database within the function.

Laravel - Creating a Dynamic URL using a Database String

I am with a bit of a stuggle here. I managed to create the dynamic URL using the following code:
Home Page Controller
$satellites = DB::table('satellites')->get();
return view('pages/home', ['satellites' => $satellites]);
Blade File
#foreach($satellites as $satellite)
<li>{{$satellite->satname}}</li>
#endforeach
web.php
Route::get('{norad_cat_id}', 'Satellite#show');
Controller
public function show($norad_cat_id)
{
return view('pages/satellite');
}
The URL generated is: mysite.com/12345 (where 12345 is the norad_cat_id).
This code manages to create the dynamic URLs using the norad_cat_id from the database - which is what I want. The problem is that I can replace the URL with anything and it still creates a page (ie. replace the 12345 with something not from the database and a page is still created).
What I want is only for a URL to be generated only with the norad_cat_id and if there is no matching norad_cat_id in the database, display a 404 page.
In the show method add a fetch from database if there is no record just abort
public function show($norad_cat_id)
{
$satellite = DB::table('satellites')->where('norad_cat_id', $norad_cat_id)->first();
if( ! satellite){
return abort(404);
}
return view('pages/satellite');
}
PS: abort will automatically redirect to your resources/views/errors/404.blade.php
You can do this multiple ways
Create a regex for norad_cat_id
The example shows nummeric ([0-9]+)
Route::get('{norad_cat_id}', 'Satellite#show')->where(['norad_cat_id' => '[0-9]+']);
Use findOrFail() and on fail show the 404.
try
{
$user = Satellites::findOrFail($id);
return view('norad_cats');
}
// catch(Exception $e) catch any exception
catch(ModelNotFoundException $e)
{
return view('404');
}
You can throw 404 in your controlller (for example). Just check if records exists in database - if not then return error.
Example:
public function show($cat_id)
{
$sattelites = DB::table('sattelites')->where('norad_cat_id', $cat_id)->get();
if ($satellites === NULL)
{
\App::abort(404);
}
return view('pages/sattelite', [
'satellites' => $satellites
]);
}
I think you get the idea.
Here's an example using query builder which is what I assume you're using:
public function show($norad_cat_id)
{
$norad_cat_data = DB::table('satellites')->where('norad_cat_id', $norad_cat_id)->get();
if (!is_null($norad_cat_id)
{
return view('pages/satellite');
}
\App::abort(404);
}

Laravel: How to restrict route to admin and groupmates

I am currently developing a website using Laravel.
A user belongs to 1 and only 1 group.
How do I restrict the route
Route::('/view/profile/{id}', 'ProfileController#showProfile');
to be only accessible by other users belonging to the same group. I would also like to allow the admin to access this route. However the admin does not belong to any group.
I know there are two ways to solve your problem.
You can create a custom middleware and bind it to your route.
Or you can do a simple check in your controller method.
I will give an example of the second method since it is the easiest.
Example:
// YourController.php
public function yourMethod()
{
// Get the user from authentication
$user = Auth::user();
// Check user and redirect to login when NULL
// This also can be done with auth middleware (check link in method 1)
if (!$user) return Response::redirect('yourLoginRoute');
// Check if has not group throw forbidden
if ($user->group->id != theGroupId) return App::abort(403);
}
Edit after comment #PaulLucero
So if I understand correctly only users of the same group can visit eachothers profile page (view/profile/{id}). Also you want to use a middleware to solve this problem but are unable to retrieve the route parameter {id}.
You can retrieve a parameter in Laravel 4 outside a route by using Route::input('yourParameter'). Check this and scroll down to Accessing A Route Parameter Value.
Example:
class YourMiddleware
{
public function handle($request, Closure $next)
{
// Get id from route and get user model
$user_id = Route::input('id');
$user = User::find($user_id);
// Do some checks
....
// Get user from auth
$auth_user = Auth::user();
// Do some checks
....
// If groups don't match throw 403
if ($user->group_id != $auth_user->group_id) return App::abort(403);
return $next($request);
}
}
I think this should do the trick.
create a custom middleware try like this
public function yourMethod()
{
$user = Auth::user();
if ($user->group_id == 1) {
return Response::redirect('yourRouteToGroupID-1');
else if(if ($user->group_id == 2) {)
return Response::redirect('yourRouteToGroupID-2');
else{
return App::abort(403);
}
}

codeiginter no direct access to functions

I'm having this problem about direct access to functions: for example I have this code:
controller users
function index(){
//this is my users index view, user can add,edit,delete cars
}
function details($id){
//a function where 1 car can be viewed in detail..
function add(){
//function to add car
}
Now if I go to address bar and type. localhost/myapp/users/detail it will go to the url and echo an error since $id is null. What I want is only the index is directly accessible if a user would type in the address bar. I don't want the users to go directly to myapp/users/add, etc..
CI Controller functions always must be able to handle user input (i.e. url segments), which means anyone can type in whatever they wish and make a request. You can't stop that. The best practice is to either:
Always provide default arguments
Use the URI class to get your parameters, or func_get_args()
Always validate the presence of and integrity of arguments passed to the controller, as you would with any other user input
Since it's much more common, accepted, and easier to read - just make sure to always provide defaults and validate them.
An example with your controller:
function index() {
//this is my users index view
//user can add,edit,delete cars
}
function details($id = NULL) {
if ( ! $id) {
// No ID present, maybe redirect without message
redirect('users');
}
$user = $this->user_model->get($id);
if ( ! $user) {
// ID present but no user found, redirect with error message
$this->session->set_flashdata('error_message', 'User not found');
redirect('users');
}
// We found a user, load view here etc.
}
function add() {
// Check for the presence of a $_POST value
// You could also use the Form_validation lib here
if ( ! $this->input->post('add_car')
{
$this->session->set_flashdata('error_message', 'Invalid request');
redirect('users');
}
// Try to add the car here and always redirect from here
}
The only other way is to make the method private or use CI's _underscore() naming as suggested (making it inaccessible from the url). You can still call the function in other methods if you wish, as in:
function index() {
if ($this->input->post('add_car')
{
// Call the private "_add" method
$this->_add();
}
// Load index view
}
So to make a long story short: You can't stop the requests from being made, you can only decide what to do when the request is invalid.
Add an underscore before the names of functions you want to hide:
function _details($id){
//a function where 1 car can be viewed in detail..
}
function add(){
//function to add car
}

Categories