I have three models, Clinic, Department and ClinicDepartment and has belongsToMany relation called departments from Clinic to Department using ClinicDepartment's table as pivot table, but when i using this relation, scopes from ClinicDepartment not aplying in query.
I decided to make Pivot model calling ClinicDepartmentPivotand apply those scopes to Pivot, but no luck.
Clinic model:
class Clinic extends Model
{
use SoftDeletes, ActiveOnly, HasParent;
public function departments()
{
return $this->belongsToMany(Department::class, 'clinic_departments', 'clinic_id', 'department_id')->using(ClinicDepartmentPivot::class);
}
}
Department Model:
class Department extends Model
{
use SoftDeletes, ActiveOnly;
public function clinics()
{
return $this->belongsToMany(Clinic::class, 'clinic_departments', 'department_id', 'clinic_id')->using(ClinicDepartmentPivot::class);
}
}
ClinicDepartmentPivot Model:
class ClinicDepartmentPivot extends Pivot
{
use ActiveOnly, SoftDeletes;
}
ActiveOnlyScope:
class ActiveOnlyScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where($model->getTable() . '.is_active', true);
}
}
So basicaly I want to apply global scopes to Pivot model, so when I trying to get Clinics of Department, it should check - is ClinicDepartment has is_active = 1 and not deleted.
UPD 1
My scope traits looks like this:
trait ActiveOnly
{
public static function bootActiveOnly()
{
if (!Auth::guard('admin')->check() && strpos(request()->getRequestUri(), 'admin') === false) {
static::addGlobalScope(new ActiveOnlyScope);
}
}
}
Can be used by any model.
Okay, with some workaround I finally found a working solution that does not look scrappy.
public function clinics()
{
return $this->belongsToMany(Clinic::class, 'clinic_departments', 'department_id', 'clinic_id')
->where(function (Builder $query) {
$query->where('clinic_departments.is_active', 1)
->whereNull('clinic_departments.deleted_at');
});
}
Actual query looks like this:
select `clinics`.*, `clinic_departments`.`department_id` as `pivot_department_id`, `clinic_departments`.`clinic_id` as `pivot_clinic_id` from `clinics` inner join `clinic_departments` on `clinics`.`id` = `clinic_departments`.`clinic_id` where (`clinic_departments`.`is_active` = 1 and `clinic_departments`.`deleted_at` is null)
Thanks all for the ideas.
You are missing something here:
To assign a global scope to a model, you should override a given
model's boot method and use the addGlobalScope method
Laravel Docs on scope
Your models should look like these:
class Clinic extends Model
{
use SoftDeletes, ActiveOnly, HasParent;
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ActiveOnlyScope);
}
public function departments()
{
return $this->belongsToMany(Department::class, 'clinic_departments', 'clinic_id', 'department_id')->using(ClinicDepartmentPivot::class);
}
}
class Department extends Model
{
use SoftDeletes, ActiveOnly;
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ActiveOnlyScope);
}
public function clinics()
{
return $this->belongsToMany(Clinic::class, 'clinic_departments', 'department_id', 'clinic_id')->using(ClinicDepartmentPivot::class);
}
}
Related
So I have the following relational structure:
User - UserTask - Task
My pivot model (UserTask) needs to access a property from the Task model.
So I have an accessor function in my UserTask model in which I need to access the Task->document_upload_required property.
Any one know how I can access this?
Note:
I cannot set the accessor in the parent model because I need to use the Media functions set on the pivot model.
Here is how I've defined the relationships:
Task:
class Task extends Model
{
public function users()
{
return $this->belongsToMany(User::class, 'user_task')->using('App\Models\UserTask')->withPivot('completed');
}
}
UserTask:
class UserTask extends Pivot implements HasMedia
{
use HasMediaTrait;
public function getCompletedAttribute()
{
return "Need to access parent attribute here";
}
}
User:
class User extends Authenticatable
{
use HasApiTokens, Notifiable, Billable;
public function tasks()
{
return $this->belongsToMany(Task::class);
}
}
UPDATE:
Here is my pivot (UserTask) table that I am trying to fetch data from:
Here is the function in my pivot model:
public function isComplete() {
if($this->task->document_upload_required) {
return $this->getMedia()->isEmpty() && $this->completed;
} else {
return $this->completed;
}
}
public function getCompletedAttribute()
{
return $this->isComplete();
}
Here is how I make the call to join the models:
$sections = $this->model->with(['subsections.tasks.users' => function($q){
$q->where('users.id', '=', Auth::id());
}])->where('parent', NULL)->doesntHave('assessments')->sorted()->get();
You need to declare the relationship first and then access its property, like this:
public function task()
{
return $this->belongsTo(Task::class);
}
public function getCompletedAttribute()
{
return $this->task->completed;
}
EDIT:
$collection = $this->model->with(['subsections.tasks.users' => function($q){
$q->where('users.id', '=', Auth::id());
}])->where('parent', NULL)->doesntHave('assessments')->sorted()->get();
$collection->each(function($subsection) {
$subsection->tasks->each(function($task) {
$task->users->each(function($user) {
dump($user->pivot->completed);
});
});
});
dd();
I have a pivot model called UserTask in which I have an accessor function:
class UserTask extends Pivot implements HasMedia
{
use HasMediaTrait;
public function getCompletedAttribute()
{
return $this->getMedia()->isEmpty() && $this->completed;
}
public function task()
{
return $this->belongsTo(Task::class);
}
}
I specify the relation in my Task model like this:
class Task extends Model
{
public function users()
{
return $this->belongsToMany(User::class, 'user_task')->using('App\Models\UserTask')->withPivot('completed');
}
}
I get the following error:
"message": "Undefined property: App\Models\UserTask::$completed",
Anyone know why this is happening?
Try this accessor function:
public function getCompletedAttribute($value)
{
return $this->getMedia()->isEmpty() && $value;
}
I have following tables.
Users
id
name
Events
id
name
Cards
id
name
Transfers
id
event_id
card_id
I added the belongs to relationship in the Card.php as well as in Event.php
class Card extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function events()
{
return $this->belongsToMany(Event::class,'transfers');
}
}
class Event extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
public function user()
{
return $this->belongsTo(User::class);
}
public function cards()
{
return $this->belongsToMany(Card::class,'transfers');
}
}
I was trying to use the following statements in my controller both of them returned error
> echo count($user->events->cards->where([['id', '=',
> '57']])->find());die; //$cards is not defined.
> echo count($user->events->cards()->where([['id', '=',
> '57']])->find());die; // method cards() is not defined.I tried this after reading a tutorial
Any help on resolving this issue is appreciated.
Thanks in advance.
You can make your life a lot easier by using the hadManyThrough relationship:
class User extends Model {
public function cards() {
return $this->hasManyThrough(Card::class, Event::class);
}
}
Then in principle you can do something like :
$user->cards()->where(['id', '=', '57']);
Consider the following table structure:
user table
id
name
lang_region_id
lang_region table
id
lang_id
region_id
lang table
id
name
region table
id
name
Fairly new to the Laravel framework, but trying to setup Eloquent models and relationships to an existing database. I want to establish the relationship between my user model and the lang and region models. The lang_region table defines what language and region combinations are available and then we can link each user to a valid combination.
I have read through the Laravel documentation several times looking for the proper relationship type, but is seems that the Many to Many and Has Many Through relationships are close, but since our user.id isn't used in the intermediate table I may be out of luck.
Sorry for the amateur question, but just getting used to Laravel and ORMs in general.
I would use the lang_region table as both a pivot table and a regular table with its own model.
class LangRegion extends model
{
protected $table = 'lang_region';
public function language()
{
return $this->belongsTo(Language::class, 'lang_id');
}
public function region()
{
return $this->belongsTo(Region::class);
}
public function users()
{
return $this->hasMany(User::class);
}
}
class User extends model
{
protected $table = 'user';
public function langRegion()
{
return $this->belongsTo(LangRegion::class);
}
}
class Language extends model
{
protected $table = 'lang';
public function regions()
{
$this->belongsToMany(Region::class, 'lang_region', 'lang_id', 'region_id');
}
public function users()
{
$this->hasManyThrough(User::class, LangRegion::class, 'lang_id', 'lang_region_id');
}
}
class Region extends model
{
protected $table = 'region';
public function languages()
{
$this->belongsToMany(Language::class, 'lang_region', 'region_id', 'lang_id');
}
public function users()
{
$this->hasManyThrough(User::class, LangRegion::class, 'region_id', 'lang_region_id');
}
}
If I understand what you want correctly:
class User extends Model {
private function lang_region() {
return $this->hasOne(LangRegion::class)
}
public function lang() {
return $this->lang_region()->lang();
}
public function region() {
return $this->lang_region()->region();
}
}
class LangRegion extends Model {
public function lang() {
return $this->belongsTo(Lang::class);
}
public function region() {
return $this->belongsTo(Region::class);
}
}
I have a database with the following tables and relationships:
Advert 1-1 Car m-1 Model m-1 Brand
If I want to retrieve an Advert, I can simply use:
Advert::find(1);
If I want the details of the car, I could use:
Advert::find(1)->with('Car');
However, if I also want the detail of the Model (following the relationship with Car), what would the syntax be, the following doesn't work:
Advert::find(1)->with('Car')->with('Model');
Many thanks
It's in the official documentation under "Eager Loading"
Multiple relationships:
$books = Book::with('author', 'publisher')->get();
Nested relationships:
$books = Book::with('author.contacts')->get();
So for you:
Advert::with('Car.Model')->find(1);
First you need to create your relations,
<?php
class Advert extends Eloquent {
public function car()
{
return $this->belongsTo('Car');
}
}
class Car extends Eloquent {
public function model()
{
return $this->belongsTo('Model');
}
}
class Model extends Eloquent {
public function brand()
{
return $this->belongsTo('Brand');
}
public function cars()
{
return $this->hasMany('Car');
}
}
class Brand extends Eloquent {
public function models()
{
return $this->hasMany('Model');
}
}
Then you just have to access this way:
echo Advert::find(1)->car->model->brand->name;
But your table fields shoud be, because Laravel guess them that way:
id (for all tables)
car_id
model_id
brand_id
Or you'll have to specify them in the relationship.
Suppose you have 3 models region,city,hotels and to get all hotels with city and region then
Define relationship in them as follows:-
Hotel.php
class Hotel extends Model {
public function cities(){
return $this->hasMany(City::class);
}
public function city(){
return $this->belongsTo('App\City','city_id');
}
}
City.php
class City extends Model {
public function hotels(){
return $this->hasMany(Hotel::class);
}
public function regions(){
return $this->belongsTo('App\Region','region_id');
}
}
Region.php
class Region extends Model
{
public function cities(){
return $this->hasMany('App\City');
}
public function country(){
return $this->belongsTo('App\Country','country_id');
}
}
HotelController.php
public function getAllHotels(){
// get all hotes with city and region
$hotels = Hotel::with('city.regions')->get()->toArray();
}
will adding the relation function just ask for the relation needed
public function Car()
{
return $this->belongsTo(Car::class, 'car_id')->with('Model');
}
but if you want a nested relation just use the period in the with
Advert::with('Car.Model')->find(1);
but for multi-relation use the array
Advert::with('Car','Model')->find(1);