Laravel - How to get data from a table related with pivot table - laravel

I have this model for notifications table:
class Notification extends Model
{
public function users()
{
return $this->belongsToMany(User::class, 'notification_user', 'notification_id', 'user_id');
}
}
And this method in controller for getting data from notifications where id of notifications is related to a pivot table named notification_user:
$myNotifications = DB::table('notification_user')
->join('notifications', 'notifications.id', 'notification_user.notification_id')
->where('notification_user.user_id', $userId)
->where('notification_user.seen', 0)
->get();
the result of $myNotifications is correct but I want to use Model and its relationship instead of DB.
How can I get all records in notifications where each notification related to a specific user which is not seen by the user.

You need to add ->withPivot('seen') to the relationship:
public function users()
{
return $this
->belongsToMany(User::class, 'notification_user', 'notification_id', 'user_id')
->withPivot('seen');
}
Then you can do:
Notification::whereHas('users', function ($q) use ($userId) {
$q->where('id', $userId)->where('seen', 0);
})->get();
To avoid joining users, your other option is whereExists:
Notification::whereExists(function ($q) use ($userId) {
$q
->selectRaw(1)
->table('notification_user')
->whereRaw('notifications.id = notification_user.notification_id')
->where('user_id', $userId)
->where('seen', 0);
})->get();
Should still be more performant, but not much more elegant.

You will have to define the same relation in User model as notifications and then:
$notifications = User::where('id', $user_id)->notifications()->where('seen', 0)->get();

You can use with keyword for eager loading inside your controller.
like if you have any relation defined inside your model, just add a with('modelRelation') before your get() statement in eloquent.
Happy Coding.

Related

Sort inside the with in laravel

$posts = PostUrl::with(['post' => function ($q) {
$q->orderBy('created_at', 'DESC');
}])
->where('category','like' ,'%'.$cat.'%')
->paginate(8);
How can I sort the result as per the created_at of the post inside?
When try to ->orderBy('post.created_at','DESC') it show column not found.
Add PostUrl models
public function post(){
return $this->hasMany('App\Post', 'postid')->orderBy('created_at', 'DESC');
}
Controller :
$posts = PostUrl::with(['post'])->where('category','like' ,'%'.$cat.'%')->paginate(8);
Make sure you have established correctly in your PostUrl model the relationship with your Post model (if it is so called). You should have a function similar to the following in your model in order to with() method works correctly in the controller:
public function post(){
return $this->hasMany('App\Post', 'postid');
}
This way there should be no problem for the orderBy clause to work properly.

Laravel how to get only relation data

this is my User.php relation code
public function activities()
{
return $this->hasMany(Activities::class, 'builder');
}
and this is my query to get only relation data
return User::whereHas('activities', fn($query) => $query->where('user_id', 1))
->paginate();
but it returns only user data without appling any relation, and its pagination not get to use pluck
i have also tried this
User::where('username', request()->username)->has('activities')->paginate();
but i need only get relation data not user with relation, and i prefer do it with whereHas
You need to create reverse relation for Activities model:
class Activities extends Model
{
// ...
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
}
And get all the activities using Activities builder:
$paginated = Acitivities::query()
->whereHas('user', static function(Builder $userQuery) {
$userQuery->where('name', request()->username); // Think about security!
})
->paginate();
Note: All the models must be named in singular (e.g. Activity, User, Product and etc.).

orderBy on hasMany relationship laravel

I made a "hasMany" relationship from Category model to Product model using ProductCatRel model.
I am trying to ordering my products form Category model. The "where" condition is fine, But "orderBy" is not working. Here is my code:
public function Products(){
return $this->hasMany(ProductCatRel::class,'category')
->with('Product')
->whereHas('Product', function($q){
$q->where('status', 1)->orderBy('position');
});
}
Use the following snippet may works
public function products(){
return $this->hasMany(ProductCatRel::class,'category')
->with('Product')
->whereHas('Product', function($q){
$q->where('status', 1)
});
}
$products = App\Category::find(1)->products()->orderBy('position')->get();
whereHas() only check existence and don't affect on retrieved relation data.
You should apply orderBy() in with() method. Also you need to duplicate status checking in with() method.
public function Products(){
return $this
->hasMany(ProductCatRel::class, 'category')
->with(['Product' => function ($q) {
$q->where('status', 1)->orderBy('position');
}])
->whereHas('Product', function($q) {
$q->where('status', 1);
});
}

I have encountered an logical error about fetching data from laravel eloquent relationship

I have two models Client and Group.
This is many to many relationships where the client belongs to many groups and groups have more than one client.
I want to get all the clients that not already belong to a group and pass it to the view.
Group Model:
public function clients() {
return $this->belongsToMany('App\Models\Client', 'client_group', 'group_id', 'client_id');
}
Client model:
public function documents() {
return $this->belongsToMany('App\Models\Document', 'client_document', 'client_id', 'document_id');
}
GroupsController.php
public function edit($id)
{
$group = Group::find($id);
$clients = Client::all()->where('user_id', Auth::user()->id);
return view('backend.groups.edit', compact('group', 'id', 'clients'));
}
If I understand correctly, you want clients that are not part of a group. Essentially, you need to query relationship absence:
$clients = App\Client::doesntHave('groups')->get();
If you want to have the ability to add additional where clauses:
use Illuminate\Database\Eloquent\Builder;
...
$clients = App\Client::whereDoesntHave('groups', function (Builder $query) {
$query->where('active', '=', true);
})->get();
For more information see Querying Relations

Reverse ordering Laravel eloquent eager loaded collection

I have a collection of products for a particular order like this ->
$products = $order->products()->with('store.seller')->get();
What I want to get is a $sellersCollection where,
each $seller has $stores
each $store has $products
[$seller - stores - products]
How can it be done efficiently without making another db call.
using eloquent relationship you can access this.use appropriate relationship hasOne() or hasMany() in your model.Ex. Seller->hasOne(store) and store->belongsTo(seller) like that.
Doing with eloquent way you could get the desired results as
$sellers = Seller::with('stores.products')->get();
Above will return you all sellers with their related stores and each store with their related products
class Seller extends Model{
public function stores(){
return $this->hasMany('App\Store', 'seller_id')
}
}
class Store extends Model{
public function products(){
return $this->hasMany('App\Product', 'product_id')
}
}
I believe order and products are related as m:m via pivot table so you could define their relation as belongsToMany
class Product extends Model{
public function orders(){
return $this->belongsToMany('App\Order')
}
}
Edit I want the particular $sellers who are associated with the order just made and with all the info of the products buyer ordered like quantity
$sellers = Seller::with(['stores.products.orders' => function ($query) use ($orderId) {
$query->where('id', '=', $orderId);
}])
->whereHas('stores.products.orders', function ($query) use ($orderId) {
$query->where('id', '=', $orderId);
})
->get();

Resources