Laravel relationship between 3 tables where 2 are connected via pivot - laravel

I am new to Laravel and looked already for a similiar thread but I didnt find something.
I want to use Eloquent and I got 3 Models and Tables: Testseries, Devices and Users.
The Users has a many to many relation to devices. (One User has many devices and vica versa)
And Devices has a one to many relation to testseries. (One Device has many testseries and many testeries has one device)
**
Table structure Users:**
id
username
Table structure Devices:
id
serial_number <-- its a string, not important for the structure
Table structure Testseries:
id
device_id
Devices and Users are connected via Pivot
device_user:
id
user_id
device_id
If a User is logged in, I want to show all Testseries from all Devices that are connected to the User.
I defined in the User Model:
public function devices(): \Illuminate\Database\Eloquent\Relations\BelongsToMany {
return $this->belongsToMany(Device::class);
}
And in the Device Model:
public function users(): \Illuminate\Database\Eloquent\Relations\BelongsToMany {
return $this->belongsToMany(User::class);
}
public function testseries(): \Illuminate\Database\Eloquent\Relations\HasMany {
return $this->hasMany(Testserie::class);
}
Is there any way to create function inside the User Model which can easily access to the testserie?
If someone doesnt understand what I want because my English isnt good. This function should tell what I want inside the User Model:
public function testseries() {
return $this->devices()->testseries();
}
Also I want all testseries at one query.
I tried with the each method. But its doing for each device a single query to the testserie.
I also tried it with the with method. It works, but I want all Columns from the Testseries Table, but then I have to tell all table names inside the array and I dont want the columns from the Devices table.
I expected to get a query when I call the ->get Method that I'll get all Testseries at once with a single query.

Try this :
Auth::user()->with('devices.testseries')->get();

I found a way,
I added this function to my User Model:
public function testseries(): \Illuminate\Support\Collection {
return Testserie::whereHas('device', function(Builder $query){
$query->whereHas('users', function(Builder $query){
$query->where ('user_id', '=', \Auth::user()->getKey());
});
})->get();
}
This works. I dont know if its the cleanest way. If someone has a better way. Dont be shy to share your thoughts.

Related

How to search for all associations in a relationship tree in Laravel?

I'm having a problem. I have tables that relate:
internal_clients->subsidiaries->departments->job_titles->users
I also have their respective models.
My doubt is:
How do I get all the data associated with users from the top of the tree (internal_clients)
?
I'm trying to follow the Laravel documentation using hasManyThrough.
However, in the documentation it explains only how to do it in a chain of three tables. They teach how to place an intermediate table (model) as the second parameter of the hasManyThrough method (BaseClasse::class, IntermediaryClass::class).
However, in my case that has several tables between users and internal_clients, how would I do this? What would be the intermediate table?
I would like to make a query that returns the user's internal_client, subsidiary, department and jobTitle (associated with users).
I'm trying to do it this way:
Model InternalClient
public function users()
{
return $this->hasManyThrough(User::class, InternalClient::class);
}
Controller UserController
public function allRelations($internalClientId)
{
$internalClient = InternalClient::find($internalClientId);
$users = $internalClient->users;
return response()->json($users, 201);
}
The InternalClient id arrives at the controller above.
When I access the route, the error below is returned:
In short: I would like to know if there is a way to get all the data (from all tables that are in this hierarchical tree) that are associated with the User.
I couldn't find an answer on the Stackoverflow PT-BR.
Thank you!

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 limit access from pivot table? Laravel

I have tables:
user
id
name
companies
id
name
company_user
company_id
user_id
Tables has Many To Many relationships.
As it complicated relationship for me, I can't find way how to make this limit, when user can see companies that was created by this user. (probably not well experienced)
Now I have this, but user can see any company
CompanyController:
public function show($company_id)
{
$company = Company::where('id', $company_id)->firstOrFail();
return view('company.settings', compact('company'));
}
So tip me please how to make user can see only companies created by this user.
You can do this:
public function show($company_id)
{
$company = auth()->user()->companies()->findOrFail($company_id);
return view('company.settings', compact('company'));
}
It will scope the company to the currently logged in user (through the many-to-many relationship on the User model). If none is found, it will return 404.
Since it many to many relation, you can map one company to many users, also map one user to many companies. Check if you have not mistakenly assign the company to many user
Also the above code can be written the way
public function show($company_id)
{
$company = Company::findOrFail($company_id);
return view('company.settings', compact('company'));
}

How to store & access data in one to many relationship of eloquent in laravel 5.3?

I have the following database table structure
users table
id
mobile
name
devices
id
user_id
device
ip
active
one user can have multiple devices from which user will login
now the question is how to store and access the devices for particular user
for example, user sam('id',1) has two devices android('user_id',1) and iphone('user_id',1). so when user will come and login i will have mobile no. to get the id of particular user from users table then i will run another query on devices table by user's id which i got from previous query and i have device ralated data.
but i know i am going wrong. what will be the other way .same happened when i am going to store user and related devices. first i store user and then by fetching id i store device for same user.
this is my User.php model
class User extends Model
{
protected $fillable = ['mobile','name'];
public function device(){
$this->hasMany('App\Device','tempuser_id');
}
}
Please tell me how can i deal with this by using eloquent one to many relationship.
In Model
public function devices()
{
return $this->hasMany('App\Device','user_id', 'id');
}
Add device to user
$user->devices()->save($device);
Get devices
foreach($user->devices as $device)
{
// device here
}
To save devices for a particular user, you can use
public function add(Request $request){
$device= new \App\Device;
$device->user_id = $request->user()->id;
$device->device = $request->device;
$device->ip = $request->ip;
$device->active =$request->active;
$devices->save();
}
And to retrieve devices for a user, write in your controller
$devices = \App\User::find(Auth::user()->id)->devices;

Laravel 4: Return field from related table within Model function

I have a table 'sits' and it has user_id and sitter_id columns.
Inside of my User model, I have the following functions that all work perfectly and return almost everything I need.
public function mySits()
{
return $this->hasMany('Sit', 'sitter_id');
}
public function openSits()
{
return $this->hasMany('Sit')->where('sitter_id', '=', '0');
}
They work perfectly and returns almost everything I need. I say almost because what I need to do is reference the users table to get the name of the Sitter.
In the sits table, the sitter_id maps to id in the users table which has a name field.
Can I add something to the return data in the User model methods, or would I need do something in my controller.
$user = User::find(1)->load('mySits', 'openSits');
Just create a User relationship inside your Sit model. Then access it via $sit->user->name or similar.

Resources