Polymorphic relationship with other polymorphic realtion? - laravel

I have order and return tables which have a created_by and accepted_by field where the corresponding user id is stored.
But now I would like to have multiple types for created_by and accepted_by instead of only user type. Assume a company could also create or accept the order/return.
I was thinking of a polymorphic one to many relationship.
Let’s name this table participants.
Something like:
ID
created
participantable_id
participantable_type
1
1
1
user
2
0
11
company
This works either for order or return but not both.
Is it practically to add extra colums to participants like trx_id and trx_type (order/return)?
How would the realtionships looks like to perform queries like:
$order->createdBy // should give me either user or company model
$order->acceptedBy
$return->createdBy
$return->acceptedBy
Or is there even a cleaner solution I am overlooking?
Thanks!

It would be 1:N polymorphic relationships so no need for an extra table. The structure can be found in the documentation
Your Order and Return model need to have the columns created_by_id, created_by_type, accepted_by_id, accepted_by_type.
______ (1) Company
/
Order (N) ----<
\______ (1) User
_____ (1) Company
/
Return (N) ----<
\_____ (1) User
class Order extends Model
{
public function created_by()
{
return $this->morphTo(__FUNCTION__, 'created_by_type', 'created_by_id');
}
public function accepted_by()
{
return $this->morphTo(__FUNCTION__, 'accepted_by_type', 'accepted_by_id');
}
}
class Return extends Model
{
public function created_by()
{
return $this->morphTo(__FUNCTION__, 'created_by_type', 'created_by_id');
}
public function accepted_by()
{
return $this->morphTo(__FUNCTION__, 'accepted_by_type', 'accepted_by_id');
}
}
class User extends Authenticatable
{
public function created_orders()
{
return $this->morphMany(Order::class, 'created_by');
}
public function accepted_orders()
{
return $this->morphMany(Order::class, 'accepted_by');
}
public function created_returns()
{
return $this->morphMany(Return::class, 'created_by');
}
public function accepted_returns()
{
return $this->morphMany(Return::class, 'accepted_by');
}
}
class Company extends Model
{
public function created_orders()
{
return $this->morphMany(Order::class, 'created_by');
}
public function accepted_orders()
{
return $this->morphMany(Order::class, 'accepted_by');
}
public function created_returns()
{
return $this->morphMany(Return::class, 'created_by');
}
public function accepted_returns()
{
return $this->morphMany(Return::class, 'accepted_by');
}
}

Related

Laravel Eloquent HasManyThrough through 3 tables with pivot tables

I need to make a list of scopes from my positions->areas->scopes on my Booking Model.
My tables look like that:
Booking
id
...
Position
id
booking_id
...
Area
id
..
Position_areas
id
area_id
position_id
Scope
id
...
Area_Scopes
id
area_id
scope_id
And this are my relations:
class Booking extends Model
{
...
public function positions()
{
return $this->hasMany(BookingPosition::class);
}
public function areas()
{
return $this->hasManyThrough(Area::class, PositionsAreas::class, 'area_id', 'id', 'position_id', 'area_id');
}
...
}
class BookingPosition extends Model
{
...
public function booking()
{
return $this->belongsTo(Booking::class);
}
public function areas()
{
return $this->belongsToMany(Area::class, 'position_areas', 'position_id', 'area_id')
->using(PositionsAreas::class);
}
...
}
class PositionsAreas extends Pivot
{
...
protected $table = 'position_areas';
public function positions(){
return $this->belongsTo(BookingPosition::class);
}
public function areas(){
return $this->belongsTo(Area::class);
}
...
}
class Area extends Model
{
...
public function bookingPositions()
{
return $this->belongsToMany(
BookingPosition::class
)->using(PositionsAreas::class);
}
public function scopes()
{
return $this->belongsToMany(Scope::class, table: 'scope_areas');
}
...
}
class Scope extends Model
{
...
public function areas(){
return $this->belongsToMany(Area::class, table: 'scope_areas');
}
...
}
And I want to have a list of all areas on my booking model, but I don't know how to achieve that.
So that I can do something like that
...
$booking->load('scopes');
[
id
date
...
scopes => [
{...},
{...}
]
]
I tried to create pivot models for position_areas but i cant even get a list of areas on my booking model.
I couldn't figure out how to solve this with a relation like hasManyThrough but as workaround I make all scopes available in my $bookings like that.
$booking = Booking::find($booking->id);
$booking->scopes = $booking->positions
->pluck('areas')
->flatten()
->pluck('scopes')
->flatten()
->pluck('name')
->unique()
->values()
->all();

Access to relation on another model

I have three tables, Owner, Garages, Orders
Owner has "n" garages and each garage belongs to one owner,
Each garage can have many orders,
Now is it possible to only get orders from Owner model with relation instance?
Owner model:
public function garages()
{
return $this->hasMany(Garage::class);
}
Garage model:
public function owner()
{
return $this->belongsTo(Owner::class);
}
public function orders()
{
return $this->hasMany(Order::class);
}
First of all, you should elaborate on how your models are defined. Guessing about how your database schemas are, you must fix your relationships:
Owner.php
public function garages()
{
return $this->hasMany(Garage::class);
}
public function orders()
{
return $this->hasManyThrough(Order::class, Garage::class);
}
Garage.php
public function owner()
{
return $this->belongsTo(Owner::class);
}
public function orders()
{
return $this->hasMany(Order::class);
}
Order.php
public function garage()
{
return $this->belongsTo(Garage::class);
}
Saying that, you can access your Owner's orders by doing
$owner = Owner::findOrFail($owner_id);
$orders = $owner->orders;

Polymorphic BelongsTo relationship in Laravel

How could I set relationships to use just one table (model_types) in Laravel to store types for cars and bikes?
Car model
public function carTypes()
{
return $this->hasMany(CarType::class);
}
CarType model (inverse relationship):
public function car()
{
return $this->belongsTo(Car::class);
}
Bike model
public function bikeTypes()
{
return $this->hasMany(BikeType::class);
}
BikeType model (inverse relationship):
public function bike()
{
return $this->belongsTo(Bike::class);
}
There are 2 options I can think of to solve this problem, the first being a simple table using a type column and the other is using polymorphic relations which is a little overkill.
The first option is to have a type column on your model_types table which you could use to determine the type and adding constants in your ModelType class like this:
const TYPE_CAR = 1;
const TYPE_BIKE = 2;
Then you can easily access the data like so, so from the Car model it's
public function modelType()
{
return $this->belongsTo(ModelType::class)->where('type', ModelType::TYPE_CAR);
}
If you wanted to access it from the model_types table it would look like this:
public function cars()
{
return $this->hasMany(Car::class)
}
public function bikes()
{
return $this->hasMany(Bike::class)
}
You have it reversed.
A car can belong to one car type, but one car type can apply to many cars.
The same goes for bikes.
You don't need a polymorphic relationship.
Car model
public function carType()
{
return $this->belongsTo(ModelType::class);
}
Bike model
public function bikeType()
{
return $this->belongsTo(ModelType::class);
}
ModelType model
public function cars()
{
return $this->hasMany(Car::class);
}
public function bikes()
{
return $this->hasMany(Bike::class);
}
Not sure about inverse relationship, but in your Car model you should use
public function carTypes()
{
return $this->hasMany(ModelType::class, 'foreign_key', 'local_key');
}
Car Model:
public function carTypes() {
return $this->hasMany(ModelType::class);
}
Bike Model:
public function bikeTypes() {
return $this->hasMany(ModelType::class);
}
ModelType Model:
public function car() {
return $this->belongsTo(Car::class, 'modeltype_car_id');
}
public function bike() {
return $this->belongsTo(Bike::class, 'modeltype_bike_id');
}

Laravel how to define 3 relationships with one model?

I have a Model which is called Championship. Championship may have 3 judges which are called Main Judge, Main Secretary and Judge Operator.
All of them linked to User Model and stored in the database as user ID.
My relationships looks like this
class Championship extends Model
{
protected $table = 'championships';
public function mainJudge()
{
return $this->hasOne('App\User', 'id', 'main_judge');
}
public function mainSecretary()
{
return $this->hasOne('App\User', 'id', 'main_secretary');
}
public function judgeOperator()
{
return $this->hasOne('App\User', 'id','judge_operator');
}
}
But I can't undertand how to define inverse relationship in User model
class User extends Authenticatable
{
public function sex()
{
return $this->belongsTo('App\Models\Sex');
}
public function player()
{
return $this->hasOne('App\Models\Player', 'user_id');
}
public function championship()
{
????
}
You just have to add it like you are adding other relations :
public function championship()
{
return $this->belongsTo('App\Championship');
}
When you do :
$championship = Championship::find($id);
$mainJudge = $championship->mainJudge;
$mainSecretary = $championship->mainSecretary;
// All objects will be exactly same
dd($mainJudge->championship,$mainSecretary->championship,$championship);
I assume all the user records have a foreign key to championships table championship_id
When you call the $user->championship relation it will return you the championship wrt to its foreign key championship_id
No need to worry you are just confusing the inverse relations:
See it this way:
Your mainJudge, mainSecretary, judgeOperators are of type App\User and every user have a championship_id when you will call the (App\User)->championship it will always return you its respective championship or null if the championship_id is empty.
Its just matter of perspective.
Just try the above code it will clear out your confusion.

join table in laravel

I have 3 table in laravel:
class General extends Mode
{
public function populars()
{
return this->hasMany('App\Popular');
}
}
enter code here
and
class Popular extends Model
{
public function general()
{
return this->belongsTo('App\General');
}
}
and
class Specific extends Model
{
public function popular(){
return this->belongsTo('App\Popular');
}
}
...
how to join tables and return this list result:
1. generals
2.popular
3.Specific
I assume Popular has many Specific, you could add another mapping in Popular model as
class Popular extends Model
{
public function general()
{
return this->belongsTo('App\General');
}
public function specific()
{
return this->hasMany('App\Specific');
}
}
Doing with eloquent way you could write it as
$generals = General::with('populars.specific')->get();
Using query builder you could join them as
DB::table('general as g')
->join('popular as p', 'g.id','=','p.general_id')
->join('specific as s', 'p.id','=','p.popular_id')
->get();

Resources