How to add multiple condition with wherePivot belongsToMany relation - laravel

I am working with Laravel 7. I have 3 tables
table_1
id
table_1_table_2
id_table_1 (fk to table_1)
id_table_2 (fk to table_2)
value (string)
hidden (bool)
table_2
id
So what i want is to get all entries in table that's connected to my Object in table_1.
So i did this :
public function table2() {
return $this->belongsToMany(table_2,'table_1_table_2','id_table_1','id_table2')->withPivot(['value','hidden']);
}
Works great. Now I want only those who are not hidden. So i did
public function table2NotHidden() {
return $this->belongsToMany(table_2,'table_1_table_2','id_table_1','id_table2')->wherePivot('hidden',0)->withPivot(['value','hidden']);
}
Works great Expect I need them where hidden == 0 but also if hidden == null
And I tried several things like ->where(function($query){...}) ->wherePivot(function($query){...}) etc... but nothing seems to work.

you can try nested where:
public function table2NotHidden() {
return $this->belongsToMany('table_2','table_1_table_2','id_table_1','id_table2')->
where(function($query){ $query->wherePivot('hidden',0)->orWherePivot('hidden',null);
});
}
or you can use #Dilip Hirapara solution:
->wherePivotIn('hidden', [0, null]);
return $this->belongsToMany(table_2,'table_1_table_2','id_table_1','id_table2')->where(function ($q) {
$q->orWhereNull('table_1_table_2.hidden')
->orWhere('table_1_table_2.hidden',0);
})

Related

Add attribute to Laravel model

I have user model, and I want to add if this user is qualified or not, I have some query to determine that,
User.php
....
public function getIsQualifiedAttribute($value)
{
return $this->qualified()->first() ? true : false;
}
public function scopeQualified($query)
{
return $query->where("years_of_experience",">=",5);
}
and this is how I want to print it
{{$user->is_qualified}}
but I can't make it work, it keeps giving me wrong value.
Laravel accessors does not have parameter
try to change your method like this
public function getIsQualifiedAttribute()
{
return $this->qualified()->first() ? true : false;
}
You don't need to do another query to this same table if you already have the model instance you want to check an attribute for. Just have the accessor check the years_of_experience field of the model:
public function getIsQualifiedAttribute()
{
return $this->years_of_experience >= 5;
}
{{ $user->is_qualified ? 'Y' : 'N' }}
With your current setup you are doing a query to the database to get the first record which has years_of_experience >= 5 every time the accessor was hit. If any record in that table has years_of_experience >= 5 that will return true.

Laravel get result from query in side query by Eloquent in one object

I have two tables:
main_presentations
so here i have "id" and "isEnabled";
child_presentations
And here i have "id" , "isEnabled" and "idParent";
I want to select in one object this is my code:
public function MainSlider(MainPresentation $MainPresentations, ChildPresentation $ChildPresentations)
{
$MainPresentations = MainPresentation::where('isEnabled', true)->get();
foreach ($MainPresentations as $MainPresentation) {
$AnArray[] = ChildPresentation::where([
['idParent', $MainPresentation['id']],
['isEnabled', true]
])->get();
}
return $AnArray;
}
but this is the result:
enter image description here
What you are doing is executing a query per result, which can be ineffective when it starts getting bigger.
You can:
Use querybuilder
As it follows, you just build a query starting on ChildPresentation, set a relation to MainPresentation table by id and get the collection
public function MainSlider()
{
$childPresentations = ChildPresentation::join('main_presentations','main_presentations.id','child_presentations.idParent')
->where('child_presentations.isEnabled', true)->where('main_presentations.isEnabled', true)->get();
return $childPresentations;
}
If you want all the MainPresentations with their respective ChildPresentations, only the enables ones.
You can take advantage of Laravel relationships and eager loading.
https://laravel.com/docs/5.6/eloquent-relationships
First, set the relationships in your MainPresentation model
In MainPresentation.php
public function childPresentation {
return $this->hasMany('App\ChildPresentation', 'idParent', 'id');
}
Your MainSlider function would be:
(Btw, no idea why you're receiving two arguments if you're overriding them but doesn't matter)
public function MainSlider() {
$mainPresentations = MainPresentation::with(['childPresentations' => function ($advancedWith) {
child_presentation.isEnabled is true
$advancedWith->where('isEnabled', true);
}])
->where('isEnabled', true)->get()->toArray();
return $mainPresentations;
}
This will return an array of MainPresentations that contain an array of child_presentations, with all their childs.
This translates to two queries:
Select * from main_presentations where isEnabled = true;
Select * from child_presentations where isEnabled= true and id in (in the first query);
Laravel then does background work to create the structure you desire when you write ->toArray()
Note: If you have a $visible array in your MainPresentation model, be sure to add: 'childPresentation' to it, otherwise the toArray will not agregage the childs to the parent.
Second note: I advise following some standards whenever you're writing code, usually functions are named camelCase and variables are camelCase.

Laravel hasManyThrough, with belongs to between the other two models

Not sure how clear is the question title, I will try to elaborate:
Tables:
repairs (Model: Repair):
id
id_supplier
id_store
suppliers (Model: Supplier):
id
store (Model: Store):
id
Relations:
Repair:
public function supplier() {
return $this->belongsTo('App\Supplier', 'id_supplier');
}
Supplier:
public function repairs() {
return $this->hasMany('App\Repair', 'id_supplier');
}
Store:
public function repairs() {
return $this->hasMany('App\Repair', 'id_store');
}
What i need from here is to get the collection of all suppliers a given store worked with, through the repairs that were made there, so my first thought it was hasManyThrough, but no ideia what to pass as 4º parameter:
Store:
public function suppliers() {
return $this->hasManyThrough('App\Supplier', 'App\Repair', 'id_supplier', '<NO IDEIA WHAT'S HERE>');
}
What am I missing? Is this the right way?
I think you can't use HasManyThrough here. Try something like this in your code:
$store = Store::with('repairs.supplier')->find($id_store);//eager load
$repairs = $store->repairs->pluck('supplier');//get array of suppliers id
$suppliers = (new Collection($repairs))->unique();//get unique collection of suppliers (without duplicates)
where $id_store is id of store which suppliers you want to get

Laravel Query to Many to many table with optional conditions

I have 3 tables as follow
dealer
id - dealer_name
specialties
id - name
dealer_specialty
id - dealer_id - specialty_id
So Dealer and Speciality model have many to many relation ship so in their models they looks like
Dealer.php
public function specialties()
{
return $this->belongsToMany('App\Models\Specialty');
}
In Speciality.php
public function dealers()
{
return $this->belongsToMany('App\Models\Dealer');
}
Now I have a scenario, where user can filter the result. Like at first whole dealers table will be shown. Now user can filter result with specialties and dealer name. So I have made route with optional parameters. And on my controller I am checking if param ins't empty put a where condition. Its working only with dealer_name as its where condition is referring to its own table. I got problem when I need to put where condition with specialty table.
My code looks like
$dealerArray = DB::table('dealers');
if(!empty($speciality )) {
// how to put where condition like get all dealers with specialit id 4, if this condition matches. I have tried following but its definitely generating error.
$dealerArray->specialities()->where('blah blah blah');
//I have also tried whereHas..
}
if(!empty($keyword)) {
$dealerArray->where('dealer_name','Like','%'.$keyword.'%');
}
return $dealerArray->get() ;
So finally I want to know how can I put an option condition that If I have to filter dealers from specialty id, how can I do that.
Try this one
In the Dealer.php
public function specialties()
{
return $this->belongsToMany(Speciality::class, 'dealer_specialty', 'dealer_id', 'specialty_id');
}
In Speciality.php
public function dealers()
{
return $this->belongsToMany(Dealer::class, 'dealer_specialty', 'specialty_id', 'dealer_id');
}
Query
$dealerArray = new Dealer();
if (!empty($speciality)) {
// how to put where condition like get all dealers with speciality id 4,
// if this condition matches. I have tried following but its definitely generating error.
$dealerArray = $dealerArray->whereHas('specialties', function ($query) use ($speciality) {
$query->where('specialty_id', $speciality);
});
//I have also tried whereHas..
}
if (!empty($keyword)) {
$dealerArray = $dealerArray->where('dealer_name', 'Like', '%' . $keyword . '%');
}
return $dealerArray->get();

Laravel 5 Pivot Table Extra Field

What I’m trying to do is when a new candidate is created an extra field is automatically populated in the joining pivot table with a random sting.
Here is my pivot table:
Result Table (pivot)
id cert_number candidate_id qualification_id
1 ? 17 2
2 ? 17 1
3 ? 57 1
So in my candidate controller I have:
public function store(CandidateRequest $request)
{
$candidateInput = Input::get('candidates');
foreach ($candidateInput as $candidate)
{
$candidate = Candidate::create($candidate);
$candidate->centre()->attach(Auth::user()->centre);
$qualification_id = $request->input('qualification_id');
$candidate->qualification()->attach($qualification_id);
$cert_number = Str::random(10);
$candidate->qualification()->attach($cert_number);
}
return redirect('candidates');
}
It adds the centre_id and qualification_id perfectly but it won’t pull though the random sting into the cert_nubmer field.
In my Candidate model I have
public function result()
{
return $this->hasMany('App\Result')->withTimestamps();
}
public function qualification()
{
return $this->belongsToMany('App\Qualification', 'Results', 'candidate_id', 'qualification_id')->withPivot('status','cert_number','partial_claim')->withTimestamps();
}
and in my result model:
public function candidate()
{
return $this->belongsTo('App\Candidate')->withTimestamps();
}
public function qualification()
{
return $this->belongsTo('App\Qualification');
}
Can anyone see where Im going wrong?
Thanks.
attach does not work like that.
Let me take out two lines of code:
$candidate->qualification()->attach($qualification_id);
$candidate->qualification()->attach($cert_number);
You are trying to add the $cert_number as a qualification_id, which is why it fails. When you do this, how is Laravel supposed to know that the second line ($cert_number) is an extra pivot column? It doesn't. You have two lines of code that are exactly the same so you can't expect Laravel to know that the second line should do something different.
When you want to insert extra data into other pivot columns, you need to pass them as an array in the second argument. Something like this:
$candidate->qualification()->attach($qualification_id, ['cert_number' => $cert_number]);

Resources