Getting the result of a trailing pivot table - laravel

Basically, I have three tables which are users, position, user_position and I want to get all users with their respective positions
Note that a single user can have multiple positions
The `user_position` table consists of:
- user_id
- position_id
To illustrate... it goes something like this:
users-->user_position<--position
What I got so far is this:
User Model
public function user_positions() {
return $this->hasMany('App\Models\UserPosition', 'user_id', 'id');
}
UserPosition Model
public function positions() {
return $this->hasMany('App\Models\Position', 'position_id', 'id');
}
UserController
public function getallusers() {
$data = User::with('user_positions')->get();
return response()->json($data);
}
So far it gives me the correct result set.
For example:
[{id:1,
name:'John',
user_positions:
[{id:1,
user_id:1,
position_id: 5
},
{id:2,
user_id:1,
position_id: 9
}
]
}]
However, it is incomplete, I also wanted the positions array inside the user_positions array but I don't know or I got lost on how to associate/merge/attach (i dont know the right term) the positions function to my User Model.

What you are looking for is a BelongsToMany relation.
You could add the following relation to your User model.
public function positions()
{
return $this->belongsToMany(Position::class);
}
You could eager load them with:
User::with('positions')->get();
Result:
[{
...
"positions": [{ ...The data of the position... }]
}]

When you want to m:m relation, it's advised to use BelongsToMany, there is no need for an intermediate model for the "pivoted" table.
If you have non-eloquent standard naming conventions. Then you have to specify the table name in the 2nd parameter as followed:
return $this->belongsToMany('App\Models\Positions', 'tbl_positions_assigned');
In the 3rd and 4th parameter you specify the foreign key names.
I'd like to refer to you to the documentation Eloquent-relationships as it's very thoroughly explained over there.
One very strong thing you can do with belongsToMany is to append extra columns in the pivot table. Those are also easily obtained from the pivot table. This is useful if you wish to store extra data values specific to the model.
return $this->belongsToMany('App\Models\Positions')->wherePivot('active', 1);
With above example you could exclude certain values, that are not active in this example, when you retrieve the results from the query.

Related

Get data through pivot table in Laravel

I got 3 tables. Table 1 & 2 has their ids as foreign keys in third one(pivot).
Relations for first one is
$this->hasMany("App\Pivot","game_id");
, second is
$this->belongsToMany("App\Pivot","army_id");
and pivot has relationships with both of them i.e belongsTo.
My schema:
I tried accessing it in controller of first one like this:
$games= Game::with("armies")->get();
Result that i get is array of games where instead of individual army data , i get collection from pivot table.
I can loop through it and get it that way, is there more elegant way of doing it?
If you are using pivot table this is the way how to do it.
Games Model
public function armies()
{
return $this->belongsToMany(App\Armies::class, 'pivot_table', 'game_id', 'army_id');
}
Armies Model
public function armies()
{
return $this->belongsToMany(App\Games::class, 'pivot_table', 'army_id', 'game_id');
}
Access the relationship like this..
Controller
App\Games::first()->armies()->get();
or
App\Games::first()->armies
or
App\Games::find(1)->armies
If you're going to use an intermediate table like that I'd probably do something like this:
Games model
public function armies()
{
return $this->belongsToMany('App\Armies');
}
Armies model
public function games()
{
return $this->belongsToMany('App\Games');
}
I'd keep the table structures all the same but rename the "pivot" table to armies_games since this is what Laravel will look for by default. If you want to keep it named Pivots, you'll need to pass it in as the second argument in belongsToMany.
With this, you don't really need the Pivot model, you should just be able to do:
$armies = Game::first()->armies()->get();
or
$armies = Game::find(3)->armies()->orderBy('name')->get();
or
$game = Game::first();
foreach ($game->armies as $army) {
//
}
etc.

How can I make a relation from Table A to table C where A related to B and B is related to C in LARAVEL

How can I able display the info from "set Penalties" Table when I do something like: $loanApplication->duration->setPenalties->penalty?
LoanApplication Model:
public function loanDuration()
{
return $this->hasOne('App\LoanDuration', 'id','loan_duration_id');
}
LoanDuration Model:
public function loanApplications()
{
return $this->hasMany(LoanApplication::class);
}
You are almost there. $loadApplication->loadDuration should already give you information from the loan_durations table.
In your LoanDuration Model you should add a new relationship method like this:
public function setPenalties(): BelongsTo
{
return $this->belongsTo(<Your penalty model>);
}
This will allow you to retrieve the penalties from a LoadDuration:
$loadDuration->setPenalties;
Or with the full example, the result will be a collection of setPenalties:
$loanApplication->loadDuration->setPenalties
It could be possible that you wont get any results from the setPenalties. This is because of the name of the related column name in the database. You could either change the name of the column duration_id to loan_duration_id or specify the duration_id in the $this->belongsTo(<Your penalty model>, 'duration_id')

How to query from database when I have different foreign keys?

I am trying to query data from my database and pass the results to a view called events, the problem I have is that one of my queries will always return the same result because in the where condition the $events_id is the same always. Is there a better way to do the querying? A better logic?
This code is from my controller called EventController:
public function index()
{
$firm_id = DB::table('firms')->where('user_id', auth()->id())->value('id');
$events_id = DB::table('events')->where('firm_id', $firm_id)->value('id');
$events = DB::table('events')->where('firm_id', $firm_id)->get()->toArray();
$actual_events = DB::table('actual_events')->where('event_id', $events_id)->get()->toArray();
return view('events',['events' => $events,'actual_events' => $actual_events]);
}
Since the $events_id is the same every time, the $actual_events will only contain the first result.
The image I have uploaded shows the problem, my table's first three columns are fine. Starting from the fourth they contain repeated values:
As I guess, you need something like this:
$event_ids = DB::table('events')->where('firm_id', $firm_id)->pluck('id');
$actual_events = DB::table('actual_events')->whereIn('event_id', $event_ids)->get()->toArray();
or write about your problem in details and I will try to help you.
you just said that your tables have relation together.
in this case it's better you using the eloquent for that,
first you should type the relations in model of each table like this:
class User extends Authenticatable{
public function cities()
{
return $this->hasmany('App\City'); //you should type your relation
}
}
for relations you can use this link: laravel relationships
after that when you compact the $user variable to your view, you can use this syntax for getting the city value relation to this user: $user->cities;.

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

How to retrieve data through model?

I have Order model with another relation OrderPhoto:
public function OrderPhoto()
{
return $this->hasMany('App\OrderPhoto');
}
In turn OrderPhoto model has relation:
public function Photo()
{
return $this->belongsToMany('App\Photo');
}
So, how to get data from OrderModel with related data from third model Photo?
I guess this:
Order::with("OrderPhoto.Photo")->get();
to retrieve only data from Photo model for each Order
So, each Order has some OrderPhotos. Relationship is one to many.
But one item from OrderPhotos is related with primary key from table Photos. It is one to one relation.
My result query should be:
select `photos`.*, `ordersphoto`.`Orders_Id` from `photos` inner join `ordersphoto` on `ordersphoto`.`Photos_Id` = `photos`.`Id` where `ordersphoto`.`Orders_Id` in (1);
How to use hasManyThrough for this query?
Just having a quick look at your relationships it looks like you could create a hasManyThrough relationship on the order Model.
public function Photo {
return $this->hasManyThrough('App\OrderPhoto', 'App\Photo')
}
You may need to add the table keys to make it work
This will allow you to do:
Order::with("Photo")->get();
You can see more details here https://laravel.com/docs/5.5/eloquent-relationships#has-many-through
Update
Try this
public function Photo {
return $this->hasManyThrough('App\Photo', 'App\OrderPhoto', 'Order_id', 'Photos_id', 'id', 'id')
}
It is a little hard to get my head around your DB structure with this info but you should hopefully be able to work it out. This may also help
https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Concerns/HasRelationships.html#method_hasManyThrough

Resources