I have this query below to get the email of all users that have a registration in a specific conference.
$users = User::whereHas('registrations', function ($query) use($conferenceID) {
$query->where('conference_id', '=', $$conferenceID);
})->get();
And dd($users) shows array:2 [▼ 0 => "....mail.com" 1 => "....mail.com"]. So its working fine.
But I want to get only the emails of the users that did a registration in a specific conference ($conferenceID) and this registration has 1 or more participants associated with a specific registration type.
Do you know how to properly achieve this query? I have the code below but it shows "Call to undefined relationship [Registration] on model [App\Conference]".
$getEmailsOfAspecificRegistrationType =
Conference::with('registrations',
'Registration.registrationTypes', 'Registration.registrationTypes.participants')
->where('id', $id)->get();
Table structure and example to explain better the context:
For example there is a conference "Conference 1" that has two registration types (rt1 and rt2). And for now there are only two registrations in the conference "Conference 1". One registration was done by Jake and other by Ben. Jake did a registration with 3 participants (him, Jane and Paul). Ben only did a registration for him. The tables structure is like below.
I want to get only the emails of the users that did a registration in the conference with id "1" and this registration has 1 or more participants associated with a specific registration type, for example "rt01". So in this case I only want to get the email of the user 1 "jakeemailtest" because is the only participant that did a registration that is associated with the registration type "rt01" because the participants Jake and Jane are associated with this registration type (as is possible to check in the participants table).
Conferentes table:
id name
1 Conference 1
Users table:
id name email
1 Jake jakeemailtest#test...
2 Ben benmailtest#test...
registration types table:
id name conference_id
1 rt1 1
2 rt2 1
Participants table:
id registration_id registration_type_id name
1 1 1 Jake
2 1 1 Jane
3 1 2 Paul
4 2 2 Ben
And the registrations table:
id status user_that_did_registration conference_id
1 Incomplete 1 1
2 Incomplete 2 1
Relevant models for the question:
Users model:
public function registrations(){
return $this->hasMany('App\Registration','user_that_did_registration');
}
Registration model:
// user that did the registration
public function customer(){
return $this->belongsTo(User::class, 'user_that_did_registration', 'id');
}
public function participants(){
return $this->hasMany('App\Participant');
}
public function conference(){
return $this->belongsTo('App\Conference');
}
Conference Model:
public function registrations(){
return $this->hasMany('App\Registration', 'conference_id');
}
Participants mode:
public function registration(){
return $this->belongsTo('App\Registration');
}
public function registration_type(){
return $this->belongsTo('App\RegistrationType');
}
According to your schema it looks like your model definitions should look like
User has Registrations => Registration belongs to User
Registration has Participants => Participant belongs to Registration
Registration Type has Participants => Participant belongs to Registration Type
Conference Has Registration Types => Registration Type belongs to Conference
Conference Has Registrations => Registration belongs to Conference
Considering above your Conference model should also have following mapping
public function registration_types(){
return $this->hasMany('App\RegistrationType', 'conference_id');
}
You could go with following to get the desired users
$users = User::whereHas('registrations.participants.registration_type', function ($query) use ($conference_id, $request) {
$query->where('name', '=', $request->rype)
->where('conference_id', '=', $conference_id);
})->whereHas('registrations', function ($query) use ($conference_id) {
$query->where('conference_id', '=', $conference_id);
})->get(); // use pluck('email') instead of get to select only email
You are specifying wrong relationship names. Strings that you provide in with() method should match the relationship methods name on model. The correct way to eager load relationships is:
$getEmailsOfAspecificRegistrationType = Conference::with(
'registrations.participants'
) ->where('id', $id)->get();
Also note that, you dont need to load each relation explicitly. When you eager load nested relationships, higher order relations are automatically loaded.
Related
My question is simple.
I have 2 tables. "Users" and "Access Levels".
The Access Levels table contains the names of the available levels on the site. Something like this:
Access Level Table
id
name
1
admin
2
subscriber
And in the Users table, I'm using the access_level through foreign key. Something like this:
Users Table
id
username
access_level
1
user1
1
2
user2
2
3
user3
2
Now I'm querying all the user in usercontroller with User:all(). The results return a collection which includes the access_level id as expected. But I want to include the name of the associated access_level within the same result set/collection. I've tried searching for Eloquent relationships, but I'm not able to understand the concept.
This is the result that I'm expecting:
Array(
[id => 1,username => user1, access_level => admin],
[id => 2,username => user2, access_level => subscriber],
[id => 3,username => user3, access_level => subscriber],
)
EDIT
After applying the code as suggested by #xenooo, I see that it returns the results with a "relations" key which has the foreign_key model instance. I've done your implementation on another set of tables. This time, in place of users, its books. And category in place of access_level. This is the response that I get with dd(). I've used the following code,
$books = Book::with('category')->find(1);
dd($books);
dd of response
First you must define the relationship of your database to your model. Assuming that you have a model for AccessLevel :
// app/Models/AccessLevel.php
public function users() : HasMany
{
return $this->hasMany(User::class, 'access_level');
}
// app/Models/User.php
public function accessLevel() : BelongsTo
{
return $this->belongsTo(AccessLevel::class,'access_level');
}
To include the relationship when querying.
User::with('accessLevel')->get(); // accessLevel is the name of the function you define.
I have two tables as bellow
user:
id
name
email
1
abc
abc#...
2
xyz
xyz#...
3
abx
abx#...
books:
id
user_name
book
price
1
abc:x1
book1
10
2
xyz:x2
book1
20
3
abc:x5
book3
30
4
ab:x2
book1
10
If you notice that my 2nd table field user_name have user_name of user table plus :x and number
maybe this didn't make sense but this is my project requirements
Now when I want to query some user with books like If I search a user with ID (1)
it should give me records of 1 & 3 because of user_name
I tried this
$user = USER::with('books')
whereHas('books', function ($query) {
$query->where('user_name', 'like', 'name:%');
})->get();
Also, I tried this
USER::with('books')
->whereHas('books', function ($query) use ($name) {
$query->where('user_name', 'like', $name . ':%');
})
Also not working.
Also how to get 3rd extra column value after :x
Also, is this possible to write this query in model?
Thanks
I would suggest you that you should always store normalized data in database irrespective of the presentation layer of the data. The data can be transformed in your desired form at query level or in the app itself.
So you should introduce 2 columns in your books table
user_id
sequence
like
id
user_id
sequence
book
price
1
1
1
book1
10
2
2
2
book1
20
3
1
5
book3
30
4
3
2
book1
10
This way you can filter out the users easily and you can apply filter on user books also. To construct the user name you can use accessor and a virtual attribute in your book model which will construct the user name for you like
class Book extends Model
{
protected $appends = ['user_name'];
protected $with = ['user'];
public function getUserNameAttribute()
{
return $this->user->name .":x". $this->sequence;
}
public function user()
{
return $this->belongsTo(User::class, 'id', 'user_id');
}
}
$appends will hold the custom attributes for your models and the accessor method will construct a user name using the user() relation. So its important if you load books then you should also eager the related users so that in accessor $this->user->name will have the name from user table otherwise it will be empty, For this you can use $with property in your model which will intimate that related user should be loaded whenever books are loaded.
Now you can get the user with specific id as
User::with('books')->find(1);
Or books by the name of user as
Book::whereHas('user', function ($query) use ($name) {
$query->where('name', 'like', $name);
});
Or books by the name of user and with the number after x that is sequence
Book::whereHas('user', function ($query) use ($name, $sequence) {
$query->where('name', 'like', $name);
})->where('sequence', $sequence);
I have two table Users and Relationships. The table Relationships contains next fields:
id | user_one_id (fk to users) | user_two_id (fk to users) | status | action_user_id
The status field can be one of 4 values. 0 - pending, 1 - accepted, 2 - rejected, 3 - blocked.
Action user is those user who created or updated request. For example, user with id 1 want to be a friend with user with id 2. action_user_id will 1.
I can't organize relationships in my User model.
For example my method friends
public function friends()
{
return $this->belongsToMany(User::class, 'relationships', 'id', 'user_one_id')
->orWhere('user_two_id', $this->id);
}
creates next sql query:
select * from "users" inner join "relationships" on "users"."id" = "relationships"."user_one_id" where "relationships"."user_one_id" = ? or "user_two_id" = ?
but I understand that it is not i need.
What i need? I need 3 methods "friends", "requested" and "blackList".
The "friends" method must return all friends of current user. The "requested" method must return all friend requests to current user. And the "blackList" must return all users who are in the blocked status of current user.
Try using a where clause, based on the status to retrieve the particular data. I recreated the problem in a fresh laravel install, and I used the user class and a relationships table to reffer to two users in a relationship
//Model User: $user->friends gets the list of friends of the user
public function friends()
{
return $this->belongsToMany('App\User', 'relationships','friend_2','friend_1')->where('friendship_status','friends');
}
At the blade.php view:
#foreach(\App\User::all() as $user)
<h5>{{$user->name}}</h5>
#foreach($user->friends as $friends)
<div>
<small>Is friends with {{$friends->name}}</small>
</div>
#endforeach
#endforeach
Relationships table migration:
Schema::create('relationships', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('friend_1');
$table->unsignedbigInteger('friend_2');
$table->string('friendship_status')->default('request pending');
$table->timestamps();
});
Manually added relationships:
I have a refferal system in my application.ie, One user can reffer other.
Users table
id name
1 A
2 B
3 C
Referrals table
id referrer_id referee_id
1 1 2
2 2 3
I want to show the referrals made by a user.
User Model
public function referrals()
{
return $this->hasMany('App\Models\Referral','referee_id','id');
}
Referral Model
public function referrer_user()
{
return $this->belongsTo('Modules\User\Models\User','referrer_id','id');
}
public function referee_user()
{
return $this->belongsTo('Modules\User\Models\User','referee_id','id');
}
Defining hasMany relationship in User model and belongsTo relationship in Referrals Model, I'am not getting the desired result.
#foreach($user->referrals as $key => $referral)
{{dd($referral->referee_user->name)}}
#endforeach
This returning me the name of user itself(referrer) not the referee
You are referring the ManyToMany relationship the wrong way.
Anyways, it'll be much easier and efficient the following way.
id name referred_by
1 abc null
2 def 1
3 gfd 2
User Model
/**
* Who did he bring onboard?
*/
public function referrals(){
return $this->hasMany('....User', 'referred_by');
}
//Who brought him onboard..
public function referree(){
return $this->belongsTo('...User', 'referred_by');
}
Just check out the appropriate syntax.
I have tables to store user's menu like below:
Table: modules
id
name
status (will have values: active / inactive)
Table: menus
id
module_id
link
Table: menu_user
user_id
menu_id
join
Table: users
id
name
password
The relationship will be like:
[users]-<menu_user>-[menus]-[modules]
Modules has many Menus; and relationship between Users and Menus is many to many.
I only can get user's menu:
$data = User::with('menus')->where('id', 2);
Any how with Eloquent way that I want to have the users's menu where the modules has active status?
Another approach would be to come from the User end and use a nested relationship to the module, eg.
User::where('users.id', 1)
->with(array('menus.module' => function($query) {
$query->where('modules.status', '=', 'active');
})
)->get();
This is dependent on the following in the Models:
User
public function menus()
{
return $this->belongsToMany('Menu');
}
Menu
public function module(){
return $this->belongsTo('Module');
}
Module
public function menu(){
return $this->hasMany('Menu');
}
Glen