Laravel HasManyThrough returns empty collection - laravel

I am attempting to use HasManyThrough (which I think might be incorrect) to return the value of a column from a table via an intermediate table. From the File model I am attempting to access the Game table. The relations are:
A game can have many mods.
Many mods can have many files.
My table schema:
File Table
id - primary key
mod_id - foreign key
Mod Table
id - primary key
game_id - foreign key
Game Table
id - primary key
And this is how I am attempting to link them, I think the issue is there is only one Game for all the files I am attempting to find however I am not sure what the singular equivalent of HasManyThrough is?
In files.php the method I am attempting to use to map the relation is the following:
public function game()
{
return $this->hasManyThrough(
'App\Game',
'App\Mod',
'id',
'id',
'mod_id',
'game_id'
);
}
And I am attempting to get it via the following call:
$data = App\Files::with('game')->get();
Funny enough if I dump & die right after calling the above method it returns the game objects, but as soon as I attempt to eager load the relation, it returns an empty collection.
Any help would be greatly appreciated.

Related

How to use an array as a foreign key in a model and build a hasMany relationship in laravel

This is my schema as follows:
Medicines
id
price
description
etc..
Ecommerce Orders(has many Medicines)
id
user_id
products (array that holds the id's of the medicine's and quantity)
And in my EcommerceOrders Model i have
protected $casts = [
'products' => 'array',
];
public function items()
{
return $this->hasMany(Medicines::class,'id','products')->withTrashed();
}
What I'm trying to do is to create a relationship between ecommerceOrders and medicines so when i get the data of an order that a client has made i also get the data of the products he has orederd
How can i do this with the foreign key in this instance being an array
You need another table called a pivot table, "ecommerce_order_medicines" with the fields medicine_id, ecommerce_order_id, qty
You would have a record for each different medicine that belongs to the ecommerce order.
You should not store it the way you are doing right now, you won't be able to make any relationship with it stored as an array like that. You also are making it much more difficult to do any kind of reports in the future, because you won't be able to properly query your database when it's stored as an array with ID's and QTY in the same column with no relationship. You will likely have to process large sets of data through PHP instead which won't scale very well.

Additional conditions on a belongsToMany relation on the intermediate table

When using the belongsToMany relation in Laravel Eloquent, is it possible to add additional conditions for the intermediate table? Currently, the inserts are duplicating and I am just trying to understand how to fix it.
Here is the relation
Models/Order.php
public function addresses(): BelongsToMany
{
return $this->belongsToMany(CustomerAddress::class)
->withPivot('address_type')
->withTimestamps();
}
Here is how I save the data to the intermediate table
$tenantOrder-addresses()->attach($customerAddress->id, [
'address_type' => 'billing'
]);
Do I need to do anything else to prevent the duplicates? Below is the example of showing the duplicates. The combination being customer_address_id, order_id, address_type.
I did take a look at Eloquent belongsToMany relation with additional conditions, but this doesn't help with the resolution.
If you mean to prevent duplicate on pivot table, can add composite keys on pivot table migrations
Something like this
...
$table->primary(['customer_address_id', 'order_id', 'address_type']);
That will prevent adding new row if the customer, order, and address type in a same value.
Here's a test
Docs
I believe you are looking for syncWithoutDetaching. It helps attach without duplicated record.
Reference: https://laravel.com/docs/9.x/eloquent-relationships#syncing-associations

Using Laravel Eloquent to count how many times something exists in an efficient manner

I have a table called rentals, within each row are columns state,city,zipcode which all house ids to another table with that info. There are about 3400 rentals. I am pulling each column to display the states,city and zipcode distinctly. I need to show how many rentals are in each one. I am doing this now via ajax, the person starts typing in what they want to see and it auto completes it with the count, but its slow because of the way im doing it.
$rentals_count = Rentals::where('published',1)->get();
foreach($states as $state) {
echo $state.”-“.$rentals_count->where(‘state’,$state->id)->count();
}
Above is roughly what im doing with pieces removed because they are not related to this question. Is there a better way to do this? It lags a bit so the auto complete seems broken to a new user.
Have you considered Eager loading your eloquent query? Eager loading is used to reduce query operations. When querying, you may specify which relationships should be eager loaded using the with method:
$rental_counts = Rentals::where('published',1)->with('your_relation')->get();
You can read more about that in Laravel Documentation
$rentals = Rentals::wherePublished(true)->withCount('state')->get();
When you loop through $rentals, the result will be in $rental->state_count
Setup a relation 'state' on rentals then call it like this
$rentals_count = Rentals::where('published',1)->with('state')->get()->groupBy('state');
$rentals_count->map(function($v, $k){
echo $v[0]->state->name .' - '. $v->count();
});
Meanwhile in Rentals Model
public function state(){
return $this->hasOne(State::class, 'state'); //state being your foreign key on rentals table. The primary key has to be id on your states table
}

Get back data from the pivot table when store a many-to-many relationship

I have a many-to-many relationship between projects and surveys. I can successfully create a relationship between a survey and a project with
$userSurvey = $project->surveys()->save($survey);.
This will create a new record inside the question_survey pivot table (The pivot table contains the columns id, question_id and survey_id.)
$userSurvey will receive the newly created survey model. Is there any way to receive also the id of the new record in the question_survey pivot table?
When retrieving many to many relationships, Laravel will automatically attach the pivot to the resulting Model, so in your case, $userSurvey will automatically have an attribute called pivot that holds, well, of course, the pivot.
But by default, that pivot attribute only holds the foreign keys, so in your case, the question_id and survey_id. If you have any other extra attributes,(in your case id), simply use the withPivot method, as follows.
public function surveys()
{
return $this->belongsToMany('App\Question', 'question_survey')
->withPivot('id');
}
Now you can access the id from the pivot table:
$userSurvey->pivot->id;
Bonus, if you think that the pivot word just does not fit your wording style, just use the as method in your relationship to customize the variable name of the pivot attribute.
public function surveys()
{
return $this->belongsToMany('App\Question', 'question_survey')
->as('question_survey')
->withPivot('id');
}
Now you can access the id from the pivot table:
$userSurvey->question_survey->id;

Updating a pivot table in Eloquent

I've got a many to many relationship between a student and an institution_contact.
students should only ever have two institution_contacts and I have an attribute on the pivot table named type to be set as 1 or 2.
So, my pivot table looks like this:
institution_contact_student: id, institution_contact_id, student_id, type
I've run into difficulty in deciding how to approach the issue of adding/updating the pivot table. Let's say I have 100 students and I want to assign them a contact with the type of 1.
My current solution is to delete the contact then add it:
$students = Student::all(); // the 100 students
$contactId = InstitutionContact::first()->id; // the contact
foreach ($students as $student) {
// remove existing contact
$student
->institutionContacts()
->newPivotStatement()
->where('type', 1)
->delete();
// add new contact
$student
->institutionContacts()
->attach([$contactId => ['type' => 1]]);
}
However, I'm thinking that this is going to hit the database twice for each student, right? So would I be better off creating a model for the pivot table and removing all entries that matched the student id and the type then simply adding the new ones? Or would creating a model for the pivot table be considered bad practice and is there a better way of accomplishing this that I've missed?
Please note the reason I'm not using sync is because I'm relying on the type attribute to maintain only two contacts per student. I'm not aware of a way to modify an existing pivot without causing issues to my two contacts per student requirement.
Edit:
Instead of creating a model I could run the following code to perform the delete using DB.
DB::table('institution_contact_student') // the pivot table
->whereIn('student_id', $studentIds)
->where('type', 1)
->delete();
If I have understood your question correctly then you can use the updateExistingPivot method for updating your pivot table.But first of course you have to define the pivot in your relationship. For instance,
public function institutionContacts(){
return $this->belongsToMany('institutionContact')->withPivot('type');
}
after this, all you have to do is use the following code:
$student
->institutionContacts()
->updateExistingPivot($contactId, ["type" => 1]);
Hope this helps.

Resources