join table in laravel - laravel-5

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();

Related

Polymorphic relationship with other polymorphic realtion?

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');
}
}

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 hasManyDeepFromRelations with group by

Models and relations
class Publisher extends Model
{
use HasRelationships;
public function collections(): BelongsToMany
{
return $this->belongsToMany(Collection::class)
->orderBy('title')
->using(CollectionPublisher::class);
}
public function series(): HasManyDeep
{
return $this->hasManyDeepFromRelations($this->collections(), (new Collection())->series());
}
}
class Collection extends Model
{
use HasRelationships, Translatable;
public function editions(): HasMany
{
return $this->hasMany(Edition::class);
}
public function series(): HasManyDeep
{
return $this->hasManyDeepFromRelations($this->editions(), (new Edition)->series());
}
}
class Edition extends Model
{
use HasRelationships, LoadsRelationshipsWithoutScopes, Translatable;
public function series(): BelongsTo
{
return $this->belongsTo(Series::class);
}
public function collection(): BelongsTo
{
return $this->belongsTo(Collection::class);
}
}
And of course there is a Series model.
The problem is that the series relation on the Publisher is returning each Series as many times as there is an Edition for that Publisher in the Series
How do I trim it down so each series is only returned once?
A simple groupBy('series.id') does not work due to the full group by limitations, and I'm not sure how to get around this using the has many deep package.
I finally came up with a solution
On the Publisher model:
public function series(): Builder
{
return $this->hasManyDeepFromRelations($this->collections(), (new Collection())->series())
->getQuery()
->select('series.*')
->groupBy('series.id');
}
The getQuery() part (undocumented in Laravel) limits the scope and allows the groupBy() to work
Thanks to Jonas Staudenmeir for the help

Eloquent query on tables with relationships and a condition in a pivot table

I've various tables with these relationships, described as models
Customers
class Customers extends Model
{
public function claims()
{
return $this->hasMany(Claims::class);
}
}
Claims
class Claims extends Model
{
public function refunds()
{
return $this->hasMany(Refunds::class);
}
public function customers()
{
return $this->belongsTo(Customers::class,'customers_id');
}
}
Refunds
class Refunds extends Model
{
public function services()
{
return $this->belongsToMany(Services::class)
->withPivot(['services_id','services_amount','services_status']);
}
public function claims()
{
return $this->belongsTo(Claims::class,'claims_id');
}
}
Services
class Services extends Model
{
public function refunds()
{
return $this->belongsToMany(Refunds::class);
}
}
I need to do a query that return all rows from Customers with a row count on the pivot table refunds_services where services_id = 1 for each Customers row.
How can I do this? Is it possible? or better i use query builder and sql with several joins
Thx
you can try :
Customers::select('cliente')
->addSelect([
'countRefundService' => Customers::withCount('claims.refunds.services', function($query) {
$query->where('id', 1);
})->get();
])
->whereHas('claims.refunds.services', function ($query) {
$query->where('id', 1);
} )
->get();

How to get data from table related through pivot table?

I have 4 tables: countries, activities, country_activities and packages.
countries and activities are related through pivot table country_activity, and packages is related to country_activity.
Now, How do I eager load all packages related to each activity in a country?
class Country extends Model
{
public function activities() {
return $this->belongsToMany('App\Models\Activity','country_activities')->using('App\Models\CountryActivity')->as('country_activities');
}
}
class Activity extends Model
{
public function countries() {
return $this->belongsToMany('App\Models\Country','country_activities')->using('App\Models\CountryActivity')->as('country_activities');
}
}
class Package extends Model
{
public function country_activities() {
return $this->belongsToMany('App\Models\CountryActivity');
}
}
class CountryActivity extends Pivot
{
protected $table = 'country_activities';
public function packages() {
return $this->hasMany('App\Models\Package');
}
}
So, this worked for me.
class Country extends Model
{
public function activities() {
return $this->belongsToMany('App\Models\Activity','country_activities')->using('App\Models\CountryActivity')->withPivot(['id'])->as('country_activities');
}
Now, In my controller, I do this
$country = Country::with(['activities'=> function($q) {$q->where('name','Trekking');}])->where('name','Nepal')->first(['id','name']);
$country->activities->map(function ($i){
$i->country_activities->load('packages');
return $i;
});
I did something similar in a project i worked on. I'm not sure it will work but it's worth the shot:
$country = Country::find(1);
$country->activities = $contry->activities()->get()->each(function ($i, $k){
$i->packages = $i->pivot->packages;
//$i->makeHidden('pivot'); -> This is useful if you want to hide the pivot table
});
var_dump($country);

Resources