I want to get the projects by the Auth::user() and company_id. I created the following:
Database:
projects:
- id
- name
- company_id
project_users:
- id
- project_id
- user_id
users:
- id
- name
- email
companies:
- id
- name
So I want to get the current user projects which belongs to company_id.
I tried the following with User Modal -> return $this->hasManyThrough('App\ProjectUsers', 'App\Project'). $user->projects->where('company_id', 1) but it returns all the data (also with company_id 2,3,4 etc).
I'm looking for a solution which can filter the projects with company_id 1 out of the query.
You have to create function in model of user
public function projectusers() {
return $this->hasMany('App\Models\project_users', 'projectID')->with('companies');
}
now create function in model projects
public function companies() {
return $this->hasMany('App\Models\companies','id', 'company_id');
}
If you are trying to limit a relation based on the results of another relation, then you need to use whereHas.
Also if you want to get the projects by some condition, I find its often most helpful to start there, with the projects.
$projects = App\Project::whereHas('company', function($q) use ($company_id) {
$q->where('id', $company_id);
})->with('users')->get();
This will grab only the projects belonging to a certain company and also eager load the users.
As you are looping, then you can get the count of the users using the relation.
foreach ($projects as $project) {
echo 'Num User: '.$project->users->count();
}
Related
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();
I need to check if a country id exists on a distant relation to a product. I only need a true or false as result. I haven't figured out how to put the query. The different relations are defined in each model:
Product - belongsToMany ShippingProfile
ShippingProfile - hasMany Methods
Method - belongsTo ShippingZone
ShippingZone - belongsToMany Countries
So if I have product id 2, and country id 5, I want to find out if the country id is available in any zone within any of the methods belonging to the profile of the product. (actually it is only one profile per product but it is defined as belongsToMany with a pivot table).
I tried to get access to countries as a first step, but I can't get access to it by using this syntax:
$prod = \App\Product::find(2)
->shipping_profiles()
->methods()->zones()->countries();
I get the error: "Call to undefined method Illuminate\\Database\\Query\\Builder::methods()
(methods() is correctly defined in shippingProfiles though).
Edit2:
Using "with", I can do a "where" check on the countries, but if I provide a non existing country, it doesn't fail - it just returns the product with the properties and a zone with an empty countries array:
return $prod = \App\Product::find(2)->with([
'shipping_profiles.methods.zone.countries' => function($query) {
$query->where('countries.id', 10000);
}])->firstOrFail();
So if you can advice any other method that will return either true/false or return the zone or null, that's what I'm looking for..
Use whereHas():
return $prod = \App\Product::whereKey(2)->whereHas(
'shipping_profiles.methods.zone.countries', function($query) {
$query->where('countries.id', 10000);
})->firstOrFail();
How do I get only users from database where they have no role assigned?
User belongs to many roles, the exact relation is:
public function roles() {
return $this->belongsToMany(Role::class, 'user_has_roles', 'user_id', 'role_id');
}
My problem is, that I do only work with Query builder, not with the model so I do not want to use relation.
EDIT:
I am working with migrations, so please no solutions when using model.
You can use doesntHave, I believe this uses QueryBuilder only.
User::doesntHave('roles')->get();
Reference: https://laravel.com/docs/5.6/eloquent-relationships
UPDATE
Using raw SQL query, you can do this.
Basically what this tries to do is to get all users where its id is not found in the user_has_roles table (meaning it doesn't have any relations)
SELECT *
FROM users
WHERE id NOT IN (SELECT user_id FROM user_has_roles)
I think you can convert this into a JOIN or something. I'm not that expert in raw SQL though.
UPDATE Trying Query Builder
$usersWithoutRoles = DB::table('users')
->whereNotIn(function ($query) {
$query->select(DB::raw('user_id'))
->from('user_has_roles')
->whereRaw('user_has_roles.user_id = users.id');
})
->get();
Reference: SQL - find records from one table which don't exist in another
You can try other alternatives there.
I have 3 tables like so:
User:
- user_id
- name
Location_user:
- loc_id
- loc_loc_id
- loc_user_id
Location:
- location_id
- location_name
So the users may belong to 4 locations so the "location_user" table will hold 4 records for that user.
At the moment I can call the users and get back a list of there locations but on an ID only basis using:
public function locations()
{
return $this->hasMany('App\Location_user', 'loc_user_id');
}
As I said this will come back with all the locations this user belongs too but I want to get the names of those location instead of the ID's or even both.
Any ideas? I am fairly new to laravel still so not had to do this yet.
EDIT:
Called by:
$results = User::with('locations')->get();
What you want is a many to many relationship not hasMany. Change your function to
public function locations()
{
return $this->BelongsToMany('App\Location_user', 'Location_user');
}
Ended up using:
public function locations() {
return $this->belongsToMany('App\Location', 'location_user', 'loc_user_id', 'loc_loc_id')->withTimestamps('loc_updated','loc_created');
}
Because I used custom column names I specified these and also included time-stamps as I needed those
I've been getting along slowly but surely with Laravel / Eloquent, but am now stumped:
entries Table:
id
user_id
group_id
content
users Table
id
faculty_id
name
group Table:
id
name
faculty Table
id
name
So entries are related to users and groups, and users are related to faculties - I've set up the basic relationships without a problem, and this enables me to find all entries by users from a certain faculty:
Faculty Model:
public function entries()
{
return $this->hasManyThrough('Entry','User');
}
Controller:
Faculty::find(Faculty-ID-here)->entries;
However, I now need to find entries by users that are from a certain faculty AND from a certain group, and I don't know how to write this combination this in Eloquent.
Hope that makes sense! Any suggestions?
Something like:
Entries::whereHas('user', function($q) {
$q->where('faculty_id', $facultyID);
})
->where('group_id', $groupID)
->get();
Assuming you have set up your 'user' relationship.