Laravel eloquent get order with current status using pivot table - laravel

I have a situation to access orders have current status: slug= "new"
Here is the scenario:
Table Statuses: with cols [id,title,slug]
Pivot Order_Status: with cols [id, order_id,status_id]
Table Orders: with cols [id, priority,client_id,...]
Where,
1 order can have many statuses
Now I want to get all the orders where the last status of that order
is "new"
I am not clear if I should use the status model to get all order or get orders and apply scope.
$status = Status::where('slug','new')->first();
$orders = $status->orders()->?
or should do something like this:
$status = Status::where('slug','new')->first();
$orders = Order::withCurrentStatus($status->id)->?
? means I don't know how to complete this also what should be in scope function.
I have to use eloquent not custom raw query.
I shall be thankful if someone can guide me here.

You can define a condition on your eager loading query
$statuses = Status::where('slug', 'new')
->with([
"orders" => function ($query) {
$query->where('some_column', '=', 'possible-value'); // single condition
//or you can also pass array on ->where()
}
])->get();
// dd($statuses); -> you can then loop through statuses and get each
// orders by $status->orders
If you don't have any conditions on your orders, you just simply eager load it
$statuses = Status::where('slug', 'new')->with('orders')->get();

Related

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();

how to get list of users who are not under belongsToMany relation under a table in laravel?

Consider the following case.
we have the Users table and Tasks table. they are in relation with belongsToMany with table task_user.
How to get the list of all users who are not under any task? i.e. their user_id is not at all under that given task or even in the task_user table.
why I need this is because like this we can only provide a list of users who are yet to be assigned a task. the task will be assigned to users and not a single user at a time.
Editing_____________
also how to filter with users based on group table? below is not working
$users = Group::with(['subscribers' => function ($q){
$q->doesntHave("tasks");
}])->whereId($gid)->latest()->get();
Assuming you've named your relationships properly, you should be able to use doesntHave("tasks"):
$tasklessUsers = User::doesntHave("tasks")->get();
doesntHave() checks for the non-existence of the supplied relationship ("tasks", in this case) and returns all objects that pass this check.
If your function name is different, use that, but the relationship should be:
User.php:
public function tasks(){
return $this->belongsToMany(Task::class, "task_user");
}
Edit: doesntHave() is the simple version, whereDoesntHave() allows a custom query. See https://laravel.com/docs/5.8/eloquent-relationships#querying-relationship-absence for full details.
Second Edit:
As stated in the comments below, with() will not filter the Model it is being called on, so this query won't work as you'd expect:
$users = Group::with(['subscribers' => function ($q){
$q->doesntHave("tasks");
}])->whereId($gid)->latest()->get();
To fix this, use a chained doesntHave() query:
$query = Group::doesntHave('subscribers.tasks')
->where('id', '=', $gid)
->latest()
->first();
// OR
$query = Group::whereHas('subscribers', function($subQuery){
$subQuery->doesntHave('tasks');
})->where('id', '=', $gid)
->latest()
->first();
$users = $query->subscribers; // Return `users` (aliased to `subscribers`)
Either approach will check the existence of subscribers that don't have any associated tasks relationship, and also only return where id is $gid.
Note: Used first() for the queries, as using id in a query should only ever return a single Group record, and get() is for returning multiple records in a Collection

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();

Laravel - Eloquent "Has", "With", "WhereHas" - What do they mean?

I've found the concept and meaning behind these methods to be a little confusing, is it possible for somebody to explain to me what the difference between has and with is, in the context of an example (if possible)?
With
with() is for eager loading. That basically means, along the main model, Laravel will preload the relationship(s) you specify. This is especially helpful if you have a collection of models and you want to load a relation for all of them. Because with eager loading you run only one additional DB query instead of one for every model in the collection.
Example:
User > hasMany > Post
$users = User::with('posts')->get();
foreach($users as $user){
$users->posts; // posts is already loaded and no additional DB query is run
}
Has
has() is to filter the selecting model based on a relationship. So it acts very similarly to a normal WHERE condition. If you just use has('relation') that means you only want to get the models that have at least one related model in this relation.
Example:
User > hasMany > Post
$users = User::has('posts')->get();
// only users that have at least one post are contained in the collection
WhereHas
whereHas() works basically the same as has() but allows you to specify additional filters for the related model to check.
Example:
User > hasMany > Post
$users = User::whereHas('posts', function($q){
$q->where('created_at', '>=', '2015-01-01 00:00:00');
})->get();
// only users that have posts from 2015 on forward are returned
The documentation has already explained the usage, so I will use SQL to explain the methods.
Example:
Assuming there is an Order (orders) has many OrderItem (order_items) and you already built the relationship between them:
// App\Models\Order:
public function orderItems() {
return $this->hasMany('App\Models\OrderItem', 'order_id', 'id');
}
These three methods are all based on a relationship.
with
Result: with() return the model object and its related results.
Advantage: It is eager-loading which can prevent the N+1 problem.
When you are using the following Eloquent Builder:
Order::with('orderItems')->get();
Laravel change this code to only two SQL:
// get all orders:
SELECT * FROM orders;
// get the order_items based on the orders' id above
SELECT * FROM order_items WHERE order_items.order_id IN (1,2,3,4...);
And then Laravel merges the results of the second SQL query with the results of the first SQL by foreign key, finally returning the collection results.
So if you selected columns without the foreign_key in a closure, the relationship result will be empty:
Order::with(['orderItems' => function($query) {
// $query->sum('quantity');
$query->select('quantity'); // without `order_id`
}
])->get();
#=> result:
[{ id: 1,
code: '00001',
orderItems: [], // <== is empty
},{
id: 2,
code: '00002',
orderItems: [], // <== is empty
}...
}]
has
Has will return the model's object when its relationship is not empty.
Order::has('orderItems')->get();
Laravel changes this code to one SQL query:
select * from `orders` where exists (
select * from `order_items` where `orders`.`id` = `order_items`.`order_id`
)
whereHas
The methods whereHas and orWhereHas put where conditions on your has queries. These methods allow you to add customized constraints to a relationship constraint.
Order::whereHas('orderItems', function($query) {
$query->where('status', 1);
})->get();
Laravel changes this code to one SQL query:
select * from `orders` where exists (
select *
from `order_items`
where `orders`.`id` = `order_items`.`order_id` and `status` = 1
)

Laravel Eloquent ORM eager loading. Relation incorrectly returned as null

I have an Eloquent ORM relationship defined as follows:
ProductConfiguration:
public function product()
{
return $this->belongsTo('Excel\Products\Product');
}
public function currency()
{
return $this->belongsTo('Excel\Currencies\Currency');
}
Product
public function productConfigurations()
{
return $this->hasMany('Excel\Products\ProductConfiguration');
}
public function productType()
{
return $this->belongsTo('Excel\Products\ProductType');
}
I expect that if I do the following that I will load all product configurations of a specified product type, with the related products, nested product type details and the product configuration currency
$results = ProductConfiguration::with(
array(
'product' => function($query) use ($product_type) {
$query->where('product_type_id' , $product_type);
},
'product.productType',
'currency'
)
)
->get();
however the returned collection has 'product' set to NULL. the Currency Relationship is there, but the product relationship is not. I can see the outputted SQL queries and the query that selects the products retrieves the correct products if I paste it directly into my sql editor
select * from `products`
where `products`.`id` in ('12', '13')
and `product_type_id` = '1'
Am I correct to think that the results from this query should be included in my collection, or is there some obvious flaw in my thinking?
I think you don't want to achieve that. Now what you get is getting all ProductConfiguration with products that are only of certain_type.
So in case you have some configuration that has other type for product you will get null because you limited results from product to only the one that has certain product type.
I might be wrong, but you probably wanted to get those ProductConfiguration that belongs to Product that is type of certain_type. In this case you should use whereHas:
$results = ProductConfiguration::
with('product', 'product.productType', 'currency')->
whereHas('product', function($q) use ($product_type)
{
$q->where('product_type_id', '=', $product_type);
})->get();
I hate to post this as an answer but since i don't have enough rep to comment so try this first:
$results = ProductConfiguration::with('product')->get();
dd($results->toArray());
See what you get, if you get some data, try this
$results = ProductConfiguartion::with(array('products' => function($query){
$query->where('product_type_id' , $product_type);
})->get();
dd($results);
See what you get, if you get null: your $product_type variable may be something you didnt expect, so try dd($product_type) to make sure its what your expecting.

Resources