Laravel retrieve data with condition from many-to-many condition - php

I have three tables:
email_accounts (list of business emails)
-------------
id
email
sender_name
users
------
id
name
email
email_accounts_users
--------------------
email_account_id
user_id
And the eloquent relationship is declared as:
User
------
public function emailAccounts()
{
return $this->belongsToMany(EmailAccount::class,'email_accounts_users');
}
EmailAccount
------------
public function users()
{
return $this->belongsToMany(User::class,'email_accounts_users');
}
I am trying to fetch rows from email_accounts that belongs to current user.
This could be correctly fetched as:
$email_acc = \DB::table('email_accounts')
->join('email_accounts_users', 'email_accounts_users.email_account_id', 'email_accounts.id')
->join('users', 'users.id', 'email_accounts_users.user_id')
->select('email_accounts.*')
->where('user_id',auth()->user()->id)
->get();
dd($email_acc);
However, I am trying to get with laravel eloquent model.
So, I tried as follows:
$email_acc = EmailAccount::with(['users' => function(){
$query->where('users_id',auth()->user()->id)
}])->get();
dd($email_acc);
However, its returning all the emails from email_accounts, rather its filtering the data from users table and sending only the currently logged in user. from users table.
However, my requirement is to fetch emails form email_accounts that belong to currently logged in users.
Like

Try This
$email_acc = EmailAccount::whereHas('users', function($query) {
$query->where('id',auth()->user()->id);
})
->get();
dd($email_acc);
It will return empty collection if the record doesn't exixts
or you can also fetch using logged in user instance
$user = auth()->user();
return $user->emailAccounts;
Make sure you defined a perfect relationship
Read Querying Relationship Existence

Specify foreign keys as follows
public function emailAccounts()
{
return $this->belongsToMany(EmailAccount::class,'email_accounts_users', 'id', 'email_account_id' );
}
EmailAccount
------------
public function users()
{
return $this->belongsToMany(User::class,'email_accounts_users', 'id', 'user_id');
}

Related

Null is given when trying to find data from pivot table

I have a Many To Many relationship between User & Wallet Models:
Wallet.php:
public function users()
{
return $this->belongsToMany(User::class,'user_wallet','wallet_id','user_id')->withPivot('balance');
}
User.php:
public function wallets()
{
return $this->belongsToMany(Wallet::class,'user_wallet','user_id','wallet_id')->withPivot('balance');
}
And the pivot table user_wallet goes like this:
Then at the Controller, I need to access the balance field:
public function chargeWallet(Request $request, $wallet, $user)
{
// $wallet is wallet_id (2) & $user is user_id (373)
$bal = Wallet::with("users")
->whereHas('users', function ($query) use ($user) {
$query->where('id',$user);
})->where('id', $wallet)->first();
dd($bal->balance);
}
But now I get null as the result of dd($bal->balance) !!
So what is wrong here? How can I properly get the balance ?
Since it is a Many to Many relationships, you have Users attached to many Wallets, and Wallets attach to many Users. For each relation between a single Wallet and a single User: you have a pivot value (pivot relation). From your query, you'll retrieve Wallet with Users, each user's having the pivot relation value attached. So to retrieve the pivot table data (for each relation) you have to use a loop (added a with callback to make sure that only Users with matching user_id are eager loaded with the Wallets):
$bal = Wallet::with(["users"=>function ($query) use ($user) {
$query->where('user_id',$user);
}])
->whereHas('users', function ($query) use ($user) {
$query->where('user_id',$user);
})->find($wallet);
To avoid repeating same callback (where user_id =) you can assign it to variable:
$callback = function ($query) use ($user) {
$query->where('user_id',$user);
};
then use it in your query:
$bal = Wallet::with(['users' => $callback])
->whereHas('users', $callback)->find($wallet);
and then use a foreach loop:
foreach ($bal->users as $value){
dd($value->pivot->balance);
}
or
if you only want to return the pivot value for the first User of the first Wallet of your query, then:
$user = $bal->users->first();
dd($user->pivot->balance);

Laravel 5.6.8 Eloquent and many to many + many to one joins

I have many to many connect with between user - cityarea.
I have also area which connect cityarea (One cityarea can connect only one area).
I have this database structure:
users
id
username
password
cityareas
id
name
area_id
cityarea_user
id
cityarea_id
user_id
areas
id
name
Next I have Models
User
public function cityareas()
{
return $this->belongsToMany('App\Cityarea');
}
Cityarea
public function area()
{
return $this->belongsTo('App\Area');
}
public function users()
{
return $this->belongsToMany('\App\User');
}
Area
public function cityareas()
{
return $this->hasMany('App\Cityarea');
}
QUESTION:
How I can get all users where areas.name = "South" with Eloquent ?
Thanks!!
By using whereHas, you can do:
$users = User::whereHas('cityareas.area', function ($query) {
$query->where('name', 'South');
})->get();
Jeune Guerrier solution is perfect, but you can use with() method of eloquent If you also need cityarea collection along with users collection.
$users = User::with('cityareas')->whereHas('cityareas.area', function ($query) {
$query->where('name', 'South');
})->get();
This is exactly what the belongs to many relationships is built for.
You simply have to do, Cityarea::where('name', 'South')->first()->users;
If you want to do something further with the query, e.g. sort by users created at, you can do
Cityarea::where('name', 'South')->first()->users()->orderBy('creaated_at', desc')->get();
Note that if there is no such Cityarea with name 'South', the ->first() query above will return null and therefore will fail to fetch the users.
A more performant way to do it programmatically is to use the whereHas approach as discussed in the comments below.

How to get all posts from the User's subscriptions

In my application, I have setup a User model that can have subscribers and subscriptions through a pivot table called subscriptions.
public function subscribers()
{
return $this->belongsToMany('Forum\User', 'subscriptions', 'subscription_id', 'subscriber_id');
}
public function subscriptions()
{
return $this->belongsToMany('Forum\User', 'subscriptions', 'subscriber_id', 'subscription_id');
}
My question is, what relationship should I use to get a list of paginated Post models (belong to a User) from the User's subscriptions?
You can use the whereHas method to filter based on relationships. Assuming your Post model has a user relationship defined, your code would look something like:
// target user
$user = \App\User::first();
$userId = $user->id;
// get all of the posts that belong to users that have your target user as a subscriber
\App\Post::whereHas('user.subscribers', function ($query) use ($userId) {
return $query->where('id', $userId);
})->paginate(10);
You can read more about querying relationship existence in the documentation.
You can do something like this
\App\Post::with(['subscriptions' => function ($query) {
$query->where('date', 'like', '%date%');
}])->paginate(15);
Or without any conditions
\App\Post::with('subscriptions')->paginate(15);

Displaying posts of users the user follows through Laravel relationships

I would like to display the posts of everyone the current user follows, ordered by date desc.
I have a many to many relationship supplying all the people the user is following.
$users = User::find(Auth::user()->id)->follow()->get();
I have a one to many relationship displaying the posts for any user.
$updates = App\User::find(?????)->updates()->orderBy('created_at', 'desc')->get();
The question mark's shows where the followers ID's need to be placed.
I can put the above query inside the for each loop but that obviously works its way through each follower rather than all posts in date order.
I suspect I may need to set a new relationship and work from the beginning. Can anyone advise.
User Model
public function updates()
{
return $this->hasMany('App\update');
}
/**
* User following relationship
*/
// Get all users we are following
public function follow()
{
return $this->belongsToMany('App\User', 'user_follows', 'user_id', 'follow_id')->withTimestamps()->withPivot('id');;;
}
// This function allows us to get a list of users following us
public function followers()
{
return $this->belongsToMany('App\User', 'user_follows', 'follow_id', 'user_id')->withTimestamps();;
}
}
Update Model
public function user_update()
{
return $this->belongsTo('App\User');
}
Thank you.
Since you want the posts, it is probably going to be easier starting a query on the Post model, and then filter the posts based on their relationships.
Assuming your Post model has an author relationship to the User that created the post, and the User has a follower relationship to all the Users that are following it, you could do:
$userId = Auth::user()->id;
$posts = \App\Post::whereHas('author.follower', function ($q) use ($userId) {
return $q->where('id', $userId);
})
->latest() // built in helper method for orderBy('created_at', 'desc')
->get();
Now, $posts will be a collection of your Post models that were authored by a user that is being followed by your authenticated user.

Creating a query in Laravel by using `with` and `where`

I'm wondering it would be possible to add a where condition to a with.
Such as:
Comment::with('Users')->where('allowed', 'Y')->get();
I was trying to find a more simple way to make queries avoiding the whereHas method which looks quite verbose:
$users = Comment::whereHas('users', function($q)
{
$q->where('allowed', 'Y');
})->get();
The raw query I want internally to generate should be like so:
select * from comments, users
where users.id = comments.user_id and
users.allowed = 'Y'
I'm used to work with CakePHP in which this queries look very simple:
$this->Comments->find('all', array('Users.allowed' => 'Y'));
The relationships I have defined are:
//Comments.php
public function Users()
{
return $this->belongsTo('Users');
}
//Users.php
public function Comments(){
return $this->hasMany('Comments');
}
You may try this
$users = User::with(array('comments' => function($q)
{
$q->where('attachment', 1);
}))->get();
Update : Alternatively you may use a where clause in your relationship in your User model
// Relation for comments with attachment value 1
// and if hasMany relation is used
public function commentsWithAttachment()
{
return $this->hasMany('Comment')->where('attachment', 1);
}
// Relation for all comments
// and if hasMany relation is used
public function comments()
{
return $this->hasMany('Comment');
}
So, you can just use
// Comments with attachment value 1
User::with('commentsWithAttachment')->get();
// All comments
User::with('comments')->get();
Update : I think you want all comments with users where attachment is 1, if this what you want then it should be Comment not User
Comment::with('user')->where('attachment', 1)->get();
In this case your relation should be
public function user()
{
return $this->belongsTo('User'); // if model name is User
}
Because one comment belongs to only one user.

Categories