laravel policy not called - laravel

Does documention hides something, or there is something hidden?
created with
php artisan make:policy AdvertisementPolicy --model=Advertisement
class AdvertisementPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any advertisements.
*
* #param \App\User $user
* #return mixed
*/
public function viewAny(User $user)
{
return false;
}
public function view(User $user, Advertisement $advertisement)
{
return false;
}
model was created with cli too
namespace App;
class Advertisement extends Model
{
Registered through:
use App\Advertisement;
use App\Policies\AdvertisementPolicy;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
Advertisement::class => AdvertisementPolicy::class,
Is here any additional steps to fulfill this policy registration with laravel 6?

There is no something hidden in documentation. You just don't read the documentation carefully.
Please take a look at the Authorizing Actions Using Policies section.
Your policy is never called, because you don't use it anywhere in your code. Atleast, if you need to run your policy for your controller resources, you need to write something like this:
<?php
namespace App\Http\Controllers;
use App\Advertisement;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class AdvertisementController extends Controller
{
public function __construct()
{
$this->authorizeResource(Advertisement::class, 'advertisement');
}
}

Related

Deleted method is not called on one of Laravel's models

I am using Laravel 6 with Voyager admin panel.
I have two different Laravel models and I am deleting their items from Voyager admin panel, deletion works well for items of both models.
I want to add some actions on model deleting so I add this code to both models.
It works for model A but not working for model B, I don't know why and how can I debug and fix it.
public static function boot() {
parent::boot();
static::deleted(function($model) {
someaction();
});
}
The only two differences between models I found
Model B has cascading deletion in its DB migration
Model B extends \TCG\Voyager\Models\User
you have to create a event bind class:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use App\Item;
use Log;
class ItemEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct()
{
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function itemDeleted(Item $item)
{
Log::info("Item Deleted Event Fire: ".$item);
}
}
register on event provider:
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
'App\Events\Event' => [
'App\Listeners\EventListener',
],
'item.deleted' => [
'App\Events\ItemEvent#itemDeleted',
]
];
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
parent::boot();
}
}
and you could test it firing on booting model like so:
class Item extends Model
{
protected $fillable = ['name', 'price'];
public static function boot() {
parent::boot();
static::deleted(function($item) {
\Log::info('Item Deleted Event:'.$item);
});
static::deleting(function($item) {
\Log::info('Item Deleting Event:'.$item);
});
}
}
You mentioned Model B has cascade delete on migration. This is most likely the cause. The delete event won't be fired because the delete happens on database level and not through Laravel. If you still need the events for this, you could handle the delete through the app instead of cascade delete. Another approach would be to watch the delete event on foreign key model, and then handle your function. Here's a related question that might help.
To further confirm if cascade delete is the cause, try manually deleting something from your Model B through the app (ModelB::find(1)->delete()).
Apart from that, if you're deleting records through query (ModelB::where('something', 1)->delete()), it won't be fired either.
I would suggest using laravel's observers in order to trigger certain code on events including creation, update, deletion...
you can see the reference here: https://laravel.com/docs/8.x/eloquent#observers
after creating the observer you add this code to your model:
public static function boot()
{
parent::boot();
MyModel::observe(MyModelObserver::class);
}

Laravel authorization/policy prevents access for everyone

I found similar title and similar asked question on this website when I was researching to solve the problem. But none of posted answers helped me. This question might be duplicated but I could not solve the problem using existing questions on StackOverflow.
I'm trying to prevent access to users who are not logged in OR who are not member of "School" model!
In "web.php" file I used "middleware("auth")" to prevent access to users who are not logged in.
Now I created a "Policy" named "SchoolPolicy" to prevent access to users who are not member of "Schools" database/model.
When I call "view" method from SchoolPolicy, it prevents access for all authorized and unauthorized users!
I also checked and I realized "School" model returns "null" when I try to catch "user_id" foreign key from "schools" table.
The below piece of code is the way I created "Schools" table using Migration:
Schema::create('schools', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained();
$table->string('school_name');
$table->string('school_address')->nullable();
$table->string('school_email');
$table->string('school_phone')->nullable();
$table->string('url');
$table->longText('descriptions')->nullable();
$table->timestamps();
});
This is the route to view any school which is created by any user (URL can be dynamic)
Route::group(['middleware' => 'auth'], function () {
Route::get('/schools/{url}', [ViewSchool::class, 'index'])->name('yourschool.show');
});
And this is "School" model. I used php artisan make:model School command to create this model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Facades\Auth;
class School extends Model{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'user_id',
'school_name',
'school_address',
'school_email',
'school_phone',
'url',
'descriptions'
];
}
In this section I created School Policy. However I used Laravel 8 but I also registered created Policy manually
SchoolPolicy
<?php
namespace App\Policies;
use App\Models\School;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class SchoolPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* #param \App\Models\User $user
* #return mixed
*/
public function viewAny(User $user)
{
//
}
/**
* Determine whether the user can view the model.
*
* #param \App\Models\User $user
* #param \App\Models\School $school
* #return mixed
*/
public function view(User $user, School $school)
{
return $user->id == $school->user_id;
}
}
In AuthServiceProvider.php I registered SchoolPolicy like this:
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use App\Models\User;
use App\Models\School;
use App\Policies\SchoolPolicy;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
School::class => SchoolPolicy::class
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
}
}
"ViewSchool.php" file where I want to use authorize method:
<?php
namespace App\Http\Controllers\Schools;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\School;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class ViewSchool extends Controller
{
public function index (School $school) {
$this->authorize('view', $school);
return view('layouts.viewschool');
}
}
I tried many ways to solve the problem, but none of them properly worked:
First Try:
public function index (School $school) {
$this->authorize('view', $school);
}
Second Try:
public function index () {
$this->authorize('view', School::class);
}
I even tried to print any output from School model but I receive "null":
public function index (School $school) {
dd($school->user_id);
}
I followed all tutorials on YouTube and official Laravel website, but in my examples I gave you, authorization doesn't work properly.
Please help me to solve this problem.
Thank you

How can I get the ID of logged in user and use it in my AppServiceProvider file in Laravel 7?

I'm working on my application using Laravel 7. I have used View Composer in my AppServiceProvider to get the count for a number of items in my database table. I have used where clause to get count for a specific logged in user. The problem is that I'm not sure how I can get the ID of currently logged in User and use in my AppServiceProvider. I have tried doing it but I'm getting Undefined variable: userId error. Please help. Thanks.
AppServiceProvider:
<?php
namespace App\Providers;
use App\Models\Project;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Auth;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$userId = Auth::id();
View::composer('client_panel.layouts.menu', function ($view) {
$view->with('newprojects', Project::where([
['status','=','1'],
['created_by','=', $userId]
])->count());
});
}
}
The error is because of , you cant call outside variable directly inside callback's. So you have to pass using use params. function ($view)($userId){
But I don't think auth user will available in service provider's So
call inside View composer.
View::composer('client_panel.layouts.menu', function ($view) {
$view->with('newprojects', Project::where([
['status','=','1'],
['created_by','=',Auth::user()->id]
])->count());
});

How to fire an event after data inserted using boot? (laravel)

I am finding a way to somewhat fire an event after the Eloquent has finished creating.
Here's my code in Branch model:
class Branch extends Model
{
//some code here
public static function boot() {
parent::boot();
self::created(function (HistoryLog $model) {
$model->tag = 'Created';
$model->description = 'This branch was created by '. ucwords(auth()->user()->name());
$model->save();
});
}
}
What I'm trying to do is, I want to create a history_log after branch was created.
But this code returns an error:
Symfony\Component\Debug\Exception\FatalThrowableError : Argument 1 passed to
App\Vehicle::App{closure}() must be an instance of App\HistoryLog, instance of
App\Vehicle given, called in D:\document\My Documents\optodph\vendor\laravel\fr
amework\src\Illuminate\Events\Dispatcher.php on line 347
Can someone point out to me what's wrong with that code? And what's the right way to achieve this?
Laravel way to do this.
Create an Observer:
php artisan make:observer BranchObserver --model=Branch
Add your logic to the Observer:
<?php
namespace App\Observers;
use App\Branch;
class BranchObserver
{
/**
* Handle the Branch "created" event.
*
* #param \App\Branch $branch
* #return void
*/
public function created(Branch $branch)
{
// Add your logic here
}
}
Register it in AppServiceProvider:
<?php
namespace App\Providers;
use App\Branch;
use App\Observers\BranchObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Branch::observe(BranchObserver::class);
}
}
$model is a new record created. Is an instance of App\Vehicle not a App\HistoryLog.
Working code might look like this:
class Vehicle extends Model
{
//some code here
public static function boot() {
parent::boot();
self::created(function ($model) {
App\HistoryLog::create([...]);
});
}
}
You can also achieve this with Eloquent Observers https://laravel.com/docs/5.8/eloquent#observers

how to get current logged-in user details in laravel 5.2?

how do i get current logged in user details in laravel 5.2 ? I have done something to get the user name but it doesn't work properly.
Here is the code that gets the current logged-in user name
<?php
namespace App\Http\Controllers;
use App\Http\Requests;
use Illuminate\Http\Request;
use DB;
use Illuminate\Contracts\Auth\User;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Auth\AuthController;
class UserProfileController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function current_user()
{
if(\Auth::check() && \Auth::user()->name) {
return 'hello';
return user()->name;
}
}
}
Here If i just return a ** return 'Hello'** in the function current_user , it works fine after checking the if condition, so i see there is no problem with if condition. But when i return user()->name it says
Call to undefined function App\Http\Controllers\user()
To access authorized user information use \Auth::user(). You probably just missing \Auth:: part, because You using correct syntax in condition.
You need to change your code a little bit.
<?php
namespace App\Http\Controllers;
use App\Http\Requests;
use Illuminate\Http\Request;
use DB;
use Illuminate\Contracts\Auth\User;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Auth\AuthController;
class UserProfileController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function current_user()
{
if(\Auth::check() && \Auth::user()->name) {
return 'Hello '.\Auth::user()->name; //this line changed
}
}
}
After that you can get the current user name.
You want to return 2 values, that's not possible. When you return something your method will stop running. So that's why you didn't get the user name.
Hope this works!

Resources