How to get data from table related through pivot table? - laravel

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

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

creating query from other tables that has the ID of the primary table in laravel

Apology for the title. I'm really not sure how to name the title correctly base from my situation. I'm new in coding that's why I am not familiar with proper terminologies.
below are the tables I am working on right now.
I am displaying the details from loan_application table. I can able to include the loan_durations and users in my #foreach but I realized I need to include also the SUM of the AMOUNT from loan_interests table and the SUM of AMOUNT from LOAN PENALTIES which gives me an headache because I can't pull them out.
LOAN APPLICATION MODEL
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LoanApplication extends Model
{
public function user()
{
return $this->hasOne('App\User', 'id','user_id');
}
public function loanDuration()
{
return $this->hasOne('App\LoanDuration', 'id','loan_duration_id');
}
public function interest()
{
return $this->belongsTo('App\LoanInterest','loan_id', 'id');
}
public function penalty()
{
return $this->belongsTo('App\LoanPenalty','loan_id', 'id');
}
}
LOAN INTEREST MODEL
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LoanInterest extends Model
{
public function loanInterest()
{
return $this->belongsTo('App\LoanApplication','loan_id', 'id');
}
}
LOAN PENALTY MODEL
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LoanPenalty extends Model
{
public function loanPenalties()
{
return $this->belongsTo('App\LoanApplication','loan_id', 'id');
}
}
for my controller
public function collectorMembers($id)
{
$collectormember = CollectorMember::where('collector_id',$id)->get();
return view('dashboard.collector-members.collector-borrowers-list', compact('collectormember'));
}
This gives this result
the CollectorMember gets the info on this table
Can you help me please? thanks a lot in advance!
There is a way to accomplish what you're after, but first I think you need to revisit your schema and relationships.
Foreign key columns should be of the same type as the referenced column. For example loan_id on the loan_interests should be int(11) just like the id column on the loan_applications table
I think you may be confusing relationship types. For example a User hasMany LoanApplications and a LoanApplication belongsTo a User. A LoanApplication hasMany LoanPenaltys and hasMany LoanInterests. A LoanPenalty and a LoanInterest both belongsTo a LoanApplication
The user_id column on the loan_penalities table is redundant because a LoanPenalty belongsTo a LoanApplication and a LoanApplication belongsTo a User
I'd recommend storing currency amounts in cents and using unsigned integers as the column type (e.g. for interest_amount)
Consider the following schema (some columns not shown):
Then consider the following models with relationships:
class User extends Model {
public function loanApplications()
{
return $this->hasMany(LoanApplication::class);
}
public function collectors()
{
return $this->belongsToMany(Collector::class);
}
}
class Collector extends Model {
public function users()
{
return $this->belongsToMany(User::class);
}
}
class LoanApplication extends Model {
public function user()
{
return $this->belongsTo(User::class);
}
public function loanDuration()
{
return $this->belongsTo(LoanDuration::class);
}
public function loanInterests()
{
return $this->hasMany(LoanInterest::class, 'loan_id');
}
public function loanPenalties()
{
return $this->hasMany(LoanPenalty::class, 'loan_id');
}
}
class LoanDuration extends Model {
public function loanApplications()
{
return $this->hasMany(LoanApplication::class);
}
}
class LoanInterest extends Model {
public function loanApplication() {
return $this->belongsTo(LoanApplication::class, 'loan_id');
}
}
class LoanPenalty extends Model {
public function loanApplication()
{
return $this->belongsTo(LoanApplication::class, 'loan_id');
}
}
Then to list all loan applications in a Resource Controller:
class LoanApplicationController extends Controller {
public function index()
{
$loan_applications = LoanApplication
::with(['user', 'loanInterests', 'loanPenalties'])
->get();
$loan_applications = $loan_applications->map(function ($loan_application) {
$loan_application->loan_penalities_sum = $loan_application->loanPenalties->sum('penalty_amount_cents');
$loan_application->loan_interests_sum = $loan_application->loanInterests->sum('interest_amount_cents');
return $loan_application;
});
return view('dashboard.loan-applications.index', compact('loan_applications'));
}
}
And in your dashboard.loan-applications.index blade template:
<table>
<tr>
<th>Username</td>
<th>Total Interest</td>
<th>Total Penalty</td>
</tr>
#foreach ($loan_applications as $loan_application)
<tr>
<td>{{$loan_application->user->username}}</td>
<td>{{$loan_application->loan_interests_sum}}</td>
<td>{{$loan_application->loan_penalties_sum}}</td>
</tr>
#endforeach
</table>
Note the above example does not include pagination; all resources are loaded at once.
The above example also assumes there should be a many-to-many relationship between collectors and users, but I would imagine a Collector should be related to the loan_applications table, not to a User.

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

Laravel Eloquent many to many relationship with translation

I have a problem with a many to many relationship and the translations of the terms.
I have 4 tables:
products
- id, price, whatever
products_lang
- id, product_id, lang, product_name
accessori
- id, active
accessori_lang
- id, accessori_id, lang, accessori_name
I'm trying to assign accessories to products with an intermediate table named:
accessori_products
this is the model for Product:
class Product extends Model {
protected $table = 'products';
public function productsLang () {
return $this->hasMany('App\ProductLng', 'products_id')->where('lang','=',App::getLocale());
}
public function productsLangAll() {
return $this->hasMany('App\ProductLng', 'products_id');
}
public function accessori() {
return $this->belongsToMany('App\Accessori', 'accessori_products');
}
}
this is the model for productLng:
class ProductLng extends Model {
protected $table = 'products_lng';
public function products() {
return $this->belongsTo('App\Product', 'products_id', 'id');
}
}
Then I have the model for Accessori:
class Accessori extends Model {
protected $table = 'accessori';
public function accessoriLang() {
return $this->hasMany('App\AccessoriLng')->where('lang','=',App::getLocale());
}
public function accessoriLangAll() {
return $this->hasMany('App\AccessoriLng');
}
public function accessoriProducts() {
return $this->belongsToMany('App\Products', 'accessori_products', 'accessori_id', 'products_id');
}
}
And the model for AccessoriLng:
class accessoriLng extends Model {
protected $table = 'accessori_lng';
public function accessori() {
return $this->belongsTo('App\Accessori', 'accessori_id', 'id');
}
}
the last model is for the relationship between the two tables above:
class ProductAccessori extends Model {
protected $table = 'accessori_products';
public function accessoriProducts() {
return $this->belongsTo('App\Product', 'accessori_id', 'products_id');
}
}
I'm trying to get the accessories of each product and to get also the translation but I'm having a lot of problem with this.
It's my first time with a many to many relation with translations too.
Can anyone put me on the right direction?
controller
$products = Product::has('accessori')->with([
'productsLang ',
'accessori' => function ($accessori){
$accessori->with([
'accessoriLang'
]);
}
])->get();
return $products;
you'll get products with accessori that has accessoriLang.

Laravel Eloquent ORM - removing rows and all the child relationship, with event deleting

I have three models that relate to each other one to many:
Country
class Country extends Model
{
protected $fillable=['name','sort'];
public $timestamps=false;
public function region(){
return $this->hasMany('App\Models\Region');
}
}
Region
class Region extends Model
{
protected $fillable=['country_id','name','sort'];
public $timestamps=false;
public function country()
{
return $this->belongsTo('App\Models\Country');
}
public function city()
{
return $this->hasMany('App\Models\City');
}
}
City
class City extends Model
{
protected $table='cities';
protected $fillable=['region_id','name','sort'];
public $timestamps=false;
public function region()
{
return $this->belongsTo('App\Models\Region');
}
}
When we remove the country automatically, remove all child item relationship, that is, removed and regions and city this country
I am doing so:
Model Country
public static function boot() {
parent::boot();
static::deleting(function($country) {
//remove related rows region and city
// need an alternative variation of this code
$country->region()->city()->delete();//not working
$country->region()->delete();
return true;
});
}
}
OR
Model Region
public static function boot() {
parent::boot();
// this event do not working, when delete a parent(country)
static::deleting(function($region) {
dd($region);
//remove related rows city
$region->city()->delete();
return true;
});
}
}
options with cascading deletes database, please do not offer
UPDATE
I found the answer
use closure for query builder, to remove related models
Model Country
public static function boot() {
parent::boot();
static::deleting(function($country) {
//remove related rows region and city
$country->region->each(function($region) {
$region->city()->delete();
});
$country->region()->delete();//
return true;
});
}
Laravel Eloquent ORM - Removing rows and all the inner relationships
Just a quick recap:
$model->related_model will return the related model.
$model->related_model() will return the relation object.
You can do either $model->related_model->delete() or $model->related_model()->get()->delete() to access the delete() method on the model.
Another way of handling the deletion of related (or sub) models is to use foreign key constraints when you write your migrations, check https://laravel.com/docs/master/migrations#foreign-key-constraints
I think you can do this in the delete function of the parent object:
public function destroy_parent($id)
{
$parent = PARENT::find($id);
foreach ($parent->childs as $child){
$child->delete();
}
$parent->delete();
return redirect(...);
}

Resources