Use relationship with policy of another model - php

I am using Laravel v5.5.14.
I have an endpoint, for App\Message in routes/api.php:
Route::group(['middleware' => 'auth:api'], function() {
Route::put('messages/{message}', 'MessageController#update')->middleware('can:view,pet');
});
I want to apply the policy of can:view,pet which is defined in my PetPolicy.php here:
namespace App\Policies;
use App\User;
use App\Pet;
use Illuminate\Auth\Access\HandlesAuthorization;
class PetPolicy
{
use HandlesAuthorization;
public function view(User $user, Pet $pet)
{
return $user->pets()->where('pet_id', $pet->id)->exists();
}
}
Every App\Message has a App\Pet I declare that pets have many messages (one-to-many) relationship in my models. And every App\User can have many App\Pet so many-to-many.
app/Pet.php:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Pet extends Model
{
protected $fillable = ['name'];
public function messages()
{
// one-to-many hasMany belongsTo
return $this->hasMany('App\Message');
}
public function users()
{
// many-to-many belongsToMany "
return $this->belongsToMany('App\User');
}
}
app/Message.php:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
protected $fillable = ['body', 'kind'];
public function pet()
{
// one-to-many hasMany belongsTo
return $this->belongsTo('App\Pet');
}
}
app/User.php:
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
// ....
public function pets()
{
// many-to-many belongsToMany "
return $this->belongsToMany('App\Pet');
}
public function messages()
{
// one-to-many hasMany belongsTo
return $this->hasMany('App\Message');
}
}
However my policy is failing, it is always giving unauthorized. Did I make a mistake somewhere?
This is my app/AuthServiceProvider.php:
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Pet' => 'App\Policies\PetPolicy',
'App\Message' => 'App\Policies\MessagePolicy'
];
public function boot()
{
$this->registerPolicies();
}
}
Thanks

Test it with this query :
namespace App\Policies;
use App\User;
use App\Pet;
use Illuminate\Auth\Access\HandlesAuthorization;
class PetPolicy
{
use HandlesAuthorization;
public function view(User $user, Pet $pet)
{
return User::where('id', $user->id)
->whereHas('pets', function ($query) use($pet) {
$query->where('id', $pet->id);
})
->exists();
}
}
Or just like this if you want :
return $user->pets->contains($pet->id);
Or like this :
return DB::table('pet_user')
->whereUserId($user->id)
->wherePetId($pet->id)
->count() > 0;

Related

how to remove children data in case many to many relationship in laravel by using observer?

there is a (card model) bleongsToMany contacts, and there is a (contact model) is bleongsToMany cards, I want when (card) get updated his children in the middle table in the relation became removed.
I'm trying to do this by using (the observer), I did all steps correctly but the issue is:
when (card model) updated his children still exist in the middle table of the relationship, I want to remove them when any update on the card.
Route:
Route::get('/test',function(){
$card = \App\Models\Card::find(1);
$card-> update([
'name' => 'firstCard1',
'user_name' =>1,
]);
return true;
});
Observer:
<?php
namespace App\Observers;
use App\Models\Card;
class CardObserver
{
public function updated(Card $card)
{
$card -> contact()-> delete();
}
}
Card Model:
<?php
namespace App\Models;
use App\Observers\CardObserver;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Card extends Model
{
use HasFactory;
protected $fillable = [
'name',
'user_id ',
];
public $timestamps = true;
protected $hidden = ['pivot'];
public function contact()
{
return $this->belongsToMany(Contact::class, 'card_contacts', 'card_id');
}
public function connection()
{
return $this->belongsTo(Connection::class, '');
}
protected static function boot()
{
parent::boot();
Card::observe(CardObserver::class);
}
}
Contact Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Contact extends Model
{
use HasFactory;
protected $fillable = [
'provider_id',
'user_id',
'contact_string'
];
public $timestamps = true;
protected $hidden = ['pivot'];
public function card(){
return $this->belongsToMany(Card::class,'card_contacts','contact_id');
}
public function user(){
return $this->belongsTo(User::class,'user_id');
}
public function provider(){
return $this->belongsTo(Provider::class,'provider_id');
}
}
Card_contact Model (the pivot table):
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CardContact extends Model
{
use HasFactory;
protected $fillable = [
'card_id',
'contact_id',
];
public $timestamps = true;
}
any help please?

Laravel Eloquent, Multidimensional Relation Accessing

I have a 4 model Totally,
Project,
Board,
Task,
SubTask
Project -> hasMany -> Board
Project -> hasManyThrough -> Task
Board -> hasMany -> Task
Board -> hasManyThrough -> SubTask
Task -> hasMany -> SubTask
This is my Project Model,
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Project extends Model
{
use HasFactory, SoftDeletes;
public function priority()
{
return $this->belongsTo(Priority::class);
}
public function users()
{
return $this->belongsToMany(User::class);
}
public function boards()
{
return $this->hasMany(Board::class);
}
public function tasks()
{
return $this->hasManyThrough(Task::class, Board::class);
}
public function subTasks()
{
}
}
Board Model,
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Board extends Model
{
use HasFactory, SoftDeletes;
public function tasks()
{
return $this->hasMany(Task::class);
}
public function subTasks()
{
return $this->hasManyThrough(SubTask::class, Task::class);
}
}
Task Model,
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Task extends Model
{
use HasFactory, SoftDeletes;
public function subTasks()
{
return $this->hasMany(SubTask::class);
}
}
How can i access Project Subtasks with eloquent relation?

Class 'app\Models\Job' not found why ? What to do?

I have this command line that doesn't work but I tried namespace app\Models\Job; or use app\Models\Job; or namespace App\Models\Job; or use App\Models\Job;.
I have also tried directly adding App\Models\Job to the command line but it didn't seem to work.
namespace App\Http\Controllers;
use app\Models\Job;
use Illuminate\Http\Request;
class JobController extends Controller
{
public function __construct(){
$this->middleware(['employer','verified'],['except'=>array('index','show','apply','allJobs','searchJobs','category')]);
}
public function index(){
$jobs = Job::latest()->limit(5)->where('status',1)->get();
$categories = Category::with('jobs')->paginate(5);
$companies = Company::get()->random(6);
return view('welcome',compact('jobs','
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Job extends Model
{
use HasFactory;
protected $fillable = ['user_id','company_id','title','slug','description','roles','category_id','position','address','type','status','last_date','number_of_vacancy','experience','gender','salary'];
public function getRouteKeyName(){
return 'slug';
}
public function company(){
return $this->belongsTo('App\Company');
}
public function users(){
return $this->belongsToMany(User::class)->withTimeStamps();
}
public function checkApplication(){
return \DB::table('job_user')->where('user_id',auth()->user()->id)->where('job_id',$this->id)->exists();
}
public function favorites(){
return $this->belongsToMany(Job::class,'favourites','job_id','user_id')->withTimeStamps();
}
public function checkSaved(){
return \DB::table('favourites')->where('user_id',auth()->user()->id)->where('job_id',$this->id)->exists();
}
}
You should do this instead:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Job; // change app to App
class JobController extends Controller
{...

laravel 5.4 - return post exact model in eloquent model

I have a Post model and two TextPost and PhotoPost models extending from it.
I want to do something like Post::find(1); and if the record with id=1 have type=photo attribute, it should return me an instance of PhotoPost model otherwise should be an instance of TextPost model. how can do this in laravel 5.4? my classes are as below:
Post.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = ['file_id', 'file', 'bot_id', 'text'];
public function bot()
{
return $this->belongsTo(Bot::class);
}
}
TextPost.php
namespace App;
use App\Traits\TextPostTrait;
class TextPost extends Post
{
use TextPostTrait;
protected $table = 'posts';
protected $fillable = ['bot_id', 'text'];
protected $attributes = ['type' => 'text'];
}
PhotoPost.php
namespace App;
use App\Traits\PhotoPostTrait;
class PhotoPost extends Post
{
use PhotoPostTrait;
protected $table = 'posts';
protected $attributes = ['type' => 'photo', 'image_watermark'];
}
PhotoPostTrait.php
namespace App\Traits;
use App\Scopes\PhotoPostScope;
trait PhotoPostTrait
{
public static function bootPhotoPostTrait()
{
static::addGlobalScope(new PhotoPostScope());
}
}
TextPostTrait.php
namespace App\Traits;
use App\Scopes\TextPostScope;
trait TextPostTrait
{
public static function bootSettingsTrait()
{
static::addGlobalScope(new TextPostScope());
}
}
TextPostScope.php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ScopeInterface;
class TextPostScope implements ScopeInterface
{
public function apply(Builder $builder, Model $model)
{
$builder->where('type', 'text');
}
public function remove(Builder $builder, Model $model)
{
}
}
PhotoPostTrait.php
namespace App\Scopes;
use \Illuminate\Database\Eloquent\Model;
use \Illuminate\Database\Eloquent\Builder;
use \Illuminate\Database\Eloquent\Scope;
class PhotoPostScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('type', '=', 'photo');
}
public function remove(Builder $builder, Model $model)
{
}
}
so I use globalScopes to categorize my post types. so basically I store them in a single table. so I should add the $table='posts'; so that laravel does not take it as a seperate model. and using traits to boot the scope. and inside the scopes I will make sure the record is a Photo or a Text.
EDIT
I found a solution by JarekTkaczyk at https://laracasts.com/discuss/channels/eloquent/multiple-models-to-same-table
But I want to know does laravel a native solution for this problem?

Laravel 5.3 + Sentinel: BadMethodCallException in Builder.php line 2450

I'm trying to build my first Laravel application by following a few guides on the internet and I'm feeling I'm missing something obvious. Here is the code.
Error
BadMethodCallException in Builder.php line 2450: Call to undefined
method Illuminate\Database\Query\Builder::addresses()
User-Model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Sentinel;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'email', 'password',
];
protected $hidden = [
'password',
'remember_token'
];
public function addresses()
{
return $this->hasMany('App\CustomerAddress');
}
}
CustomerAddress-model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class CustomerAddress extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
}
CustomerAddress-controller
<?php
namespace App\Http\Controllers;
use App\CustomerAddress;
use Illuminate\Http\Request;
class CustomerAddressController extends Controller
{
public function create(Request $request)
{
$address = new CustomerAddress();
$address->address = $request['address'];
$request->user()->addresses()->save($address);
}
}
Error appears after this piece of code:
$request->user()->addresses()->save($address);
Any ideas? Thanks and cheers
In .config/cartalyst.sentinel.php, change 'model' => 'Cartalyst\Sentinel\Users\EloquentUser' to 'model' => 'App\User' to use your user model with the addresses relation defined
In ./app/User change User extends Authenticatable to User extends \Cartalyst\Sentinel\Users\EloquentUser to extend sentinel's user to your app's User model
Finally, your controller code should now be
`$address = new CustomerAddress();
$address->address = $request->input('address');
$request->user()->addresses()->save($address);`
and everything should be peachy

Categories