Laravel : BelongstoMany relationship implementation - laravel

i have following tables
1.Shops (shop_id , company_id , name, latitude, logntitude, phone)
2.packages(package_id, company_id, cost, value, expire_date)
3.shop_packages (package_id, shop_id)
and i am trying to access this shops associated with package as below
Package Model
public function shop():BelongsToMany{
return $this->belongsToMany(Shop::class,'shop_packages','package_id','package_id');
}
Shop Model
public function package(){
return $this->belongsToMany(Package::class,'shop_packages','shop_id','shop_id');
}
now when i try below it returns me shop with empty result while there is data available ,
Package::with('shop')->where('package_id',$request['package_id'])->first();
i am using laravel 8.x for this project . Can someone please help me to sort the issue
Shop Table
Package Table
shop_packages

You entered the wrong foreign key in the relation. The belongsToMany relation should be declared like this
Package Model
public function shops():BelongsToMany{
return $this->belongsToMany(Shop::class,'shop_packages','package_id','shop_id');
//you can also just ignore the foreign keys since they follow naming standards
//return $this->belongsToMany(Shop::class,'shop_packages');
}
Shop Model
public function packages(){
return $this->belongsToMany(Package::class,'shop_packages','shop_id','package_id');
//same here
//return $this->belongsToMany(Package::class,'shop_packages');
}
You should also use plural to better express the many to many relation
Package::with('shops')->where('package_id',$request['package_id'])->first();

Related

Laravel: show data in laravel with two table

I want to display data in laravel.
This is the classrooms table:
This is the students table:
this is the classroom_student table :
I expect a result like this:
With class from the classroom table, year from the student table (the year the student was created), and data from the student table (data for each month, sample data:[2,4,6] means Jan: 2, Feb: 4, Mar: 6). I don't know how to make it. Can you help me? thank you
You need to setup a many to many relationship both of your models (classroom model and student model. It will look something like this:
class Classroom extends Model {
public function students(){
return $this->hasMany(Student:class, 'student_id');
}
}
class Student extends Model {
public function classrooms(){
return $this->hasMany(Classroom:class, 'classroom_id');
}
}
Here is also a reference to laravel docs for the exact solution:
https://laravel.com/docs/8.x/eloquent-relationships#many-to-many
You Should use HasMany Relation in both Models and while fetching data call this relation function to get data related to other model and set expected title for those data in Transformer.

Struggling with Laravel's morphable relationships

In a project, let's say that we have Customers, and each customer can have one Voucher. The voucher, though, may be for a different thing for different customers - maybe for a Hote, a Car or a Flight.
We have a table of flight voucher codes, a table of hotel voucher codes and a table of car voucher codes.
When a customer is allocated a voucher, therefore, we allocated them the next code for the relevant thing that they're getting a voucher for. But rather than have multiple tables (customer_car_voucher, customer_hotel_voucher, and so on) I would rather have a Voucher table which is, in turn, linked to the relevant voucher type.
What I want to be able to do is just go $customer->voucher->code to get the relevant code, whether that be a flight, a hotel or a car. Other vouchers may be added at a later date, you see, for different things.
I think I can do this using morphable relationships - the voucher morphsTo car, hotel and flight, so within the the voucher table there is a "voucherable_type" and a "voucherable_id". But damned if I can get it to work.
Any help, please? Am I going about it wrong?
you arte right. and for a hint use:
public function customer()
{
return $this->belongsTo(Customer::class):
}
public function voucherable()
{
return $this->morphTo();
}
in voucher model.
and for each flight,car,hotel include:
public function voucher(){
return $this->morphOne(Voucher::class,'voucherable');
}
you can see Laravel morph relationship too for more help.
In Laravel's Eloquent ORM is used for morphable relationships.
First, create two Models AirVoucher and Voucher.
First, the AirVoucher model uses the following relationship.
public function voucher()
{
return $this->morphOne(Voucher::class, 'voucherable');
}
Second, the Voucher model uses the following relationship.
public function voucherable()
{
return $this->morphTo();
}
You can use the following Laravel official relationship document for more help.
Laravel Morph Relationships.
you must use laravel Polymorphic Relationships.
in Voucher model set this model as polymorph model(function name = modelname+"able"):
public function voucherable() \Illuminate\Database\Eloquent\Relations\MorphTo
{
return $this->morphTo();
}
then in Car model (or hotel/fight) set realation(function name= polymorph name):
if each car has one voucher, use morphOne:
public function files(): \Illuminate\Database\Eloquent\Relations\MorphOne
{
return $this->morphOne(Voucher::class, 'voucherable');
}
if each car has many voucher, use morphMany:
public function files(): \Illuminate\Database\Eloquent\Relations\MorphMany
{
return $this->morphMany(Voucher::class, 'voucherable');
}
Retrieving The Relationship
$car = Car::find(1);
$vocher = $car->voucher;
laravel docs

Laravel - Eloquent relation whereHas one or more other relations

I'm learning Laravel and Laravel eloquent at the moment and now I try to solve a problem using relations in Laravel.
This is what I want to archive:
The database holds many sport clubs. A sport club has a lot of teams. Each team has games. The teams table has a column named club_id. Now I want to create Eloquent relations to get all games of a club.
Here is what I got so far:
Club model
id => PRIMARY
public function games()
{
return $this->hasMany('App\Models\Games')->whereHas('homeTeam')->orWhereHas('guestTeam');
}
Game model
home_id => FOREIGN KEY of team ; guest_id => FOREIGN KEY of team
public function homeTeam()
{
return $this->belongsTo('App\Models\Team','home_id')->where('club_id','=', $club_id);
}
public function guestTeam()
{
return $this->belongsTo('App\Models\Team','guest_id')->where('club_id','=', $club_id);
}
Team model
id => PRIMARY ; club_id => FOREIGN
In my controller all I want to do is Club::findOrFail($id)->games()
Executing the code above returns a SQL error that the games table does not have a column named club_id.
What is the correct way to create this kind of relation?
Thanks!
EDIT
Thanks to Nikola Gavric I've found a way to get all Games - but only where club teams are the home or away team.
Here is the relation:
public function games()
{
return $this->hasManyThrough('App\Models\Game','App\Models\Team','club_id','home_id');
}
How is it possible to get the games where the home_id OR the guest_id matches a team of the club? The last parameter in this function does not allow an array.
There is method to retrieve a "distant relationship with an intermediary" and it is called Has Many Through.
There is also a concrete example on how to use it which includes Post, Country and User, but I think it will be sufficient to give you a hint on how to create games relationship inside of a Club model. Here is a link, but when you open it, search for hasManyThrough keyword and you will see an example.
P.S: With right keys naming you could achieve it with:
public function games()
{
return $this->hasManyThrough('App\Models\Games', 'App\Models\Teams');
}
EDIT #01
Since you have 2 types of teams, you can create 2 different relationships where each relationship will get you one of the type you need. Like this:
public function gamesAsHome()
{
return $this
->hasManyThrough('App\Models\Games', 'App\Models\Teams', 'club_id', 'home_id');
}
public function gamesAsGuests()
{
return $this
->hasManyThrough('App\Models\Games', 'App\Models\Teams', 'club_id', 'guest_id');
}
EDIT #02
Merging Relationships: To merge these 2 relationships, you can use merge() method on the Collection instance, what it will do is, it will append all the records from second collection into the first one.
$gamesHome = $model->gamesAsHome;
$gamesGuests = $model->gamesAsGuests;
$games = $gamesHome->merge($gamesGuests);
return $games->unique()->all();
Thanks to #HCK for pointing out that you might have duplicates after the merge and that unique() is required to get the unique games after the merge.
EDIT #03
sortBy also offers a callable instead of a attribute name in cases where Collection contains numerical indexing. You can sort your Collection like this:
$merged->sortBy(function($game, $key) {
return $game->created_at;
});
When you define that Club hasMany games you are indicating that game has a foreign key called club_id pointing to Club. belongsTo is the same but in the other way. These need to be coherent with what you have on your database, that means that you need to have defined those keys as foreign keys on your tables.
Try this...
Club model
public function games()
{
return $this->hasMany('App\Models\Games');
}
Game model
public function homeTeam()
{
return $this->belongsTo('App\Models\Team','home_id');
}
public function guestTeam()
{
return $this->belongsTo('App\Models\Team','guest_id');
}
Your Query like
Club::where('id',$id)->has('games.guestTeam')->get();

Laravel Auth::user relationship

In Laravel, i´m trying to show relation elements between Auth::user (Users) and Departments. In User table i have id, name, and department_id. In Departments table I have id and name.
In user model i create
public function department()
{
return $this->belongsTo('App\Models\Department');
}
Then, in blade template I try
Auth::user()->department
But return null and doesn´t show linked departments. Null is incorrect, all users have departments. Soo, ¿Any help? ¿What´s wrong in relation?
You can try this User::with('departmento')->find(Auth::id());
This method uses less queries - the others go after the user table twice:
auth()->user()->load(['department']);
You should add 'department_id' as a second parameter ($foreignKey) when calling belongsTo method, because it will searching for departmento_id by default.
public function departamento()
{
return $this->belongsTo('App\Models\Departamento', 'department_id');
}
Or just rename User::departamento() method to User::department()
public function department()
{
return $this->belongsTo('App\Models\Departamento');
}
Relation works with Model. Auth uses the session it not uses relation
Use User Model instead
optional(User::find(Auth::id())->departmento)->department_name

Use a different column on a many-to-many relationship in Laravel 4

I've got a situation in a project where I need to form a relationship between a primary key on one table and an indexed column (not the primary key) on another. Here's a sample of the database layout:
courses table
id
level
resources table
id
courses_resources table
course_level
resource_id
In my CourseResource model I have the following:
public function courses(){
return $this->belongsToMany('Course', 'courses_resources', 'resource_id', 'course_level');
}
Which works fine.
Then in my Course model I have:
public function resources(){
return $this->belongsToMany('CourseResource', 'course_resources', 'course_level', 'resource_id');
}
Which doesn't work. When I look at the last query performed on the database, it appears Laravel is searching the course_level column using the course's ID. That makes sense, but is there any way to use the level column for this relationship?
Eloquent BelongsToMany depends on PKs, so there is no way to do that with its methods.
You need custom relation object for this, that will check for given field, instead of primary key.
A quick and hacky solution would be this:
// Course model
public function getKey()
{
$relation = array_get(debug_backtrace(1, 2), '1.object', null);
if (method_exists($relation, 'getForeignKey')
&& $relation->getForeignKey() == 'courses_resources.course_level')
{
return $this->getAttribute('level');
}
return parent::getKey();
}
However if you would like to use it in production, do some extensive testing first.

Resources