Many to many Eloquent - laravel

Ok so I tried whith your answers, I can return Invoices associated to a user but i cant get the products inside this invoice, I want to get the Invoice associated to the user with his products only.
If i mention the id of the user who creates a product and the id of the invoice, i want the query to return me the invoice with the products associated to the id of the user mentionned.
when Iam using this :
$Invoices = Commande::find(1)->whereHas('Product', function($query){
return $query->where('products.user_id', 3);
})->with('Product')->get();
I get only the Invoices.
But i want the Invoice and the products in this invoice that are associated to a certain user.

That's where the whereHas() method comes into place. You should be able to do something like this:
$user = User::find($userId); // Let's assume `$userId` is `1`
$invoices = Invoice::whereHas('products', function ($query) use ($user) {
return $query->where('products.user_id', $user->id);
})->get();
That will return all Invoice records that are associated with the $user record returned by User::find($userId) (again, in this case, user_id: 1)
You can see the full documentation here:
https://laravel.com/docs/9.x/eloquent-relationships#querying-relationship-existence
Note: You might need to adjust the model/relationship names I used in the code above to fit your needs, but the basic idea remains the same.

You can use this query to get invoices and their products belonging to a specific user
// my user id is currently authenticated, user
Invoice::query()->where('user_id', auth()->user()->id)->with('products')->paginate();

Related

Laravel eloquent for four tables

I'm new to Laravel. I am developing a project. and in this project I have 4 tables related to each other
-Users
-Orders
-OrderParcels
-Situations
When listing the parcels of an order, I want to get the information of that order only once, the user information of that order once again, and list the parcels as a table under it. so far everything ok. but I also want to display the status of the parcels listed in the table as names. I couldn't add the 4th table to the query. do you have a suggestion? I'm putting pictures that explain the structure below.
My current working code is
$orderParcels = Orders::whereId($id)
->with('parcels')
->with('users:id,name')
->first();
and my 'orders' model has method
public function parcels(){
return $this->hasMany(OrderParcels::class);
}
public function users(){
return $this->hasOne(User::class,'id','affixer_id');
}
Note[edit]: I already know how to connect like this
$orderParcels = DB::table('order_parcels as op')
->leftjoin('orders as o','op.orders_id','o.id')
->leftjoin('users as u','o.affixer_id','u.id')
->leftjoin('situations as s','op.status','s.id')
->select('op.*','o.*','u.name','s.situations_name')
->where('op.orders_id',$id)->get();
but this is not working for me, for each parcels record it returns me orders and user info. I want once orders info and once user info.
Laravel provides an elegant way to manage relations between models. In your situation, the first step is to create all relations described in your schema :
1. Model Order
class User extends Model {
public function parcels()
{
return $this->hasMany(OrderParcels::class);
}
public function users()
{
return $this->hasOne(User::class,'id','affixer_id');
}
}
2. Model Parcel
class Parcel extends Model {
public function situations()
{
return $this->hasOne(Situation::class, ...);
}
}
Then, you can retrieve all desired informations simply like this :
// Retrieve all users of an order
$users = $order->users; // You get a Collection of User instances
// Retrieve all parcels of an order
$parcels = $order->parcels; // You get a Collection of User instances
// Retrieve the situation for a parcel
$situations = $parcel->situations // You get Situation instance
How it works ?
When you add a relation on your model, you can retrieve the result of this relation by using the property with the same name of the method. Laravel will automatically provide you those properties ! (e.g: parcels() method in your Order Model will generate $order->parcels property.
To finish, in this situation where you have nested relations (as describe in your schema), you should use with() method of your model to eager load all the nested relation of order model like this :
$orders = Orders::with(['users', 'parcels', 'parcels.situations'])->find($id)
I encourage you to read those stubs of Laravel documentation :
Define model relations
Eager loading
Laravel Collection
Good luck !
Use join to make a perfect relations between tables.
$output = Orders::join('users', 'users.id', '=', 'orders.user_id')
->join('order_parcels', 'order_parcels.id', '=', 'orders.parcel_id')
->join('situations', 'situation.id', '=', 'order_parcels.situation_id')
->select([
'orders.id AS order_id',
'users.id AS user_id',
'order.parcels.id AS parcel_id',
'and so on'
])
->where('some row', '=', 'some row or variable')->get();

Laravel Eloquent Only Get One Row

So I want to show id from order table where user id is the same as currently login user id, then later used to show orders have been made by the user
$orderId = Order::select('id')->firstWhere('user_id', auth()->id())->id;
$orders = SubOrder::where('order_id', $orderId)->orderBy('created_at', 'desc')->get();
it works but it only shows the first record, after some digging later I found out that the problem is on the $orderId, it only shows the first record. but I want it to be all the records. if I change the id to get(), it shows nothing since it give the result like "id = 1" instead of the number only. also have tried to change the firstWhere into where and got error like "Property [id] does not exist on the Eloquent builder instance."
please help, thanks
If you are going to use the other Orders associated with the User soon after you get the first Order, return all the relevant Orders and then just grab the first one when you need it.
$orders = Order::where('user_id', auth()->user()->id)->get();
$firstOrder = $orders->first();
$subOrders = SubOrder::whereIn('order_id', $orders->pluck('id'))->get();
Alternatively, you could use a subOrders relationship defined on your Order model.
class Order extends Model
{
public function subOrders()
{
return $this->hasMany(SubOrder::class);
}
}
$orders = Order::where('user_id', auth()->user()->id)->get();
$firstOrder = $orders->first();
$firstOrderSubOrders = $firstOrder->subOrders;
If you're confident you're going to be working with SubOrder records, you can use eager loading on your Order to improve performance.
$orders = Order::where('user_id', auth()->user()->id)
->with('subOrders')
->get();
$firstOrder = $orders->first();
$firstOrderSubOrders = $firstOrder->subOrders;
first() will return the first id queried and stop execution.
$firstOrder = $orders->first();

Query all where list id has user id

I'm trying to get all the properties, in a watchlist(s) where the list has a user id.
The relationship is set up as follows.
Each watchlist is related to a user id. Each Property has a watchlist id.
I need all properties, in all the watchlists belonging to that user.
The watchlist gets the user_id automatically upon creation.
Here are my models
Watchlist
public function properties(){
return $this->hasMany('App\WatchedProperties');
}
public function user(){
return $this->belongsTo('App\User');
}
WatchedProperties
public function watchlist(){
return $this->belongsTo('App\Watchlist');
}
Query
Gets all books in every list disregarding user ids and list ids
$Watchlists = WatchedBooks::all();
Currently gets all books regardless of userid.
I need all books in all of the user's lists.
A user could have multiple lists
List A
List B
So something like
All books from all lists where the list id is related to user id.
This is what the Watchlist DB looks like
WatchlistDB
This is what the WatchedBooks DB looks like
Books in watchlist
Laravel has a beautiful solution for this: you can add a ->hasManyThrough relation to the user model. You can find more information about this type of relation in the Laravel documentation about Eloquent relationships.
The user model will look like this:
class User extends Model {
[...]
public function watchedBooks()
return $this->hasManyThrough('App\WatchedBook', 'App\Watchlist');
}
[...]
}
Then you can get all the WatchedBooks, associated with the user, using
$user->watchedBooks;
or
$user->watchedBooks()->yourBuilderQueryHere()->get();
whereHas allows you to query in relationships. More information on this can be found at https://laravel.com/docs/5.6/eloquent-relationships#querying-relationship-existence
$Watchlists = WatchedBooks::whereHas('watchlist', function($query) use ($user_id){
$query->where('user_id', $user_id)
})->get();
The script above gets all WatchedBooks that are associated with a Watchlist that is owned by a user ($user_id).

How to show all books not associated with a user. many-to-many relationship

I have 3 tables in my database. users, books and book_user.
book_user is the pivot table that manages the many-to-many relationship between users and books.
I have the Laravel relationship correctly setup and i am able to display all the books associated to a user using the following in Laravel.
$user = Auth::user();
return response()->json($user->books()->get());
Now i am trying to display all the books that are NOT associated to a particular user. I have been struggling for quite some time and cant seem to find anything that works. Any tips would be greatly appreciated.
If the book is not related to the user then you should not try to retrieve it via the user. Instead use the book model:
Book::whereDoesntHave('users', function ($q) {
$q->where('id', \Auth::id());
})->get();
If you want all books not belonging to any user at all, instead of all books not belonging to a particular user, you could do something like :
$books = Book::whereDoesntExists(function($query) {
$query->select('book_user.id_book')
->from('book_user')
->where('book_user.id_book', '=', 'books.id');
// Assuming that the columns on the pivot table are 'id_book' and 'id_user' and the primary key is 'id' in the 'books' table.
});
Here you fetch all books that haven't their id in the book_user pivot table's id_book column. So basically, all books not belonging to any user.

Eloquent select with() based on foreign key

I have a table with user data (users) and a table with prices (prices).
My prices table can contain multiple prices pr. user since I want to keep historical data.
I've defined my relation as a one-to-one
$this->hasOne("App\Model\Price","userid","id")->orderBy("id","desc")->take(1);
to allow me to see the users current price.
What I want to do now, is to select every user that has a current price of 100, but how do I do this? I know I could go for a left join, but as I read the documentation, it should be possible without a left join.
I've built a pseudo-query to explain what I'm after;
User::with("price")->where("prices.price","100")->get();
I've read through the documentation (Eloquent: Querying relationships), but that doesn't seem to be useful to my question.
I've also read several questions here on SO but unfortunately to no avail.
You may try this:
$currentPrice = 100;
$users = User::whereHas('price', function($query) use ($currentPrice) {
$query->where('price', $currentPrice); // price is the field name
})
->with("price")->get();
Since you have more than a single price for per user then you may also declare another relationship method to get all the price models instead of one and you may do it using something like this:
// In User model
public function prices()
{
return $this->hasMany("App\Model\Price", "userid", "id");
}
In this case, with::price will give you the last single record and with::prices will give you all the related prices. So, if you want then you may write something like the following to get all users with their all related prices who has the (latest/current) price of 100:
$currentPrice = 100;
$users = User::whereHas('price', function($query) use($currentPrice) {
$query->where('price', $currentPrice); // price is the field name
})
->with("prices") // with all prices
->get();
You can use the combination of whereHas() and with() as:
$users = User::whereHas("price", function($q) use ($currentPrice) {
$q->where("price", $currentPrice);
})
->with(["price" => function ($q) {
$query->where("price", $currentPrice);
})
->get();

Resources