Document has already explain the usage. So I am using SQL to explain these methods
Assuming there is an Order (orders)
has many OrderItem (order_items)
.
And you have already build 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.
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 merge the results of the second SQL as different from the results of the first SQL by foreign key. At last return the collection results.
So if you selected columns without the foreign_key in 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
will return the model's object that its relationship is not empty.
Order::has('orderItems')->get();
Laravel change this code to one SQL:
select * from `orders` where exists (
select * from `order_items` where `order`.`id` = `order_item`.`order_id`
)
whereHas
and orWhereHas
methods to 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 change this code to one SQL:
select * from `orders` where exists (
select *
from `order_items`
where `orders`.`id` = `order_items`.`order_id` and `status` = 1
)