conditional relationship for "with()" - laravel

I have a table called transactions and another table called cars with the below structure:
transactions
| id | date | amount | status | user_added |
| --- | ---- | ------ | ------ | ---------- |
cars
| id | plate | specs | buy_transaction | sell_transaction |
| --- | ----- | ----- | ---------------- | ----------------- |
A car has always a buy_transaction but not always a sell_transaction, situation is that I am trying to get all transactions (that might be car-related or not car-related) and include the CAR related to that transaction weather it is sold or bought, so I need to make the relationship conditional but i couldn't achieve that.
$journal = Transaction::with(
['user'=> function($query) {
$query->select('id', 'name');
},
'income',
'outcome',
'car'
])->where('date', '>=', $fromDate)->where('date', '<=', $toDate);
This is the modal class:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Transaction extends Model
{
public function income()
{
//.....
}
public function outcome()
{
//.....
}
public function user()
{
return $this->belongsTo('App\User', 'user_added', 'id');
}
// *** problem starts here ***
public function car()
{
if (transaction status == 1) {
return $this->belongsTo('App\Car', 'id', 'sell_transaction');
}
else if (transaction status == 2) {
return $this->belongsTo('App\Car', 'id', 'buy_transaction');
}
}
}
I need to stick to that query structure because the query command is longer and I am joining and including other tables, I was hoping I could make the car() belongsTo relation conditional somehow.
I followed some similar situations like this but it didn't work for me.
Thank you.

The link you post has the answer
public function soldCar()
{
return $this->belongsTo('App\Car', 'id', 'sell_transaction');
}
public function boughtCar()
{
return $this->belongsTo('App\Car', 'id', 'buy_transaction');
}
public function scopeCar($query)
{
return $query->when($this->type === '1',function($q){
return $q->with('soldCar');
})
->when($this->type === '2',function($q){
return $q->with('boughtCar');
});
}
Edit: Also, this looks like a prime example for polymorfic relations as documented here https://laravel.com/docs/5.5/eloquent-relationships#polymorphic-relations

Related

Laravel with() eager loading returning empty data

I have a one-to-many relationship in my model. Basically a Category and a Product. A product can only have one category but a category can have many products. The code below works:
return Category::select('id', 'name')->whereIn('id', $categories)->with('products')->get();
It returns with a product key and within that the product columns in the database, but when I use eager loading it just returns an empty set:
return Category::select('id', 'name')->whereIn('id', $categories)->with(['products' => function($query){
$query->limit(5);
}])->get();
I've also tried adding the return keyword like this return $query->limit(5); but still no luck.
I have also tried specifying columns like this:
return Category::select('id', 'name')->whereIn('id', $categories)->with('products:id,name')->get();
But it still returns an empty dataset.
Since I'm building an API, this is what the JSON data looks like:
[
{
"id": 161,
"name": "Health & Personal Care",
"products": []
},
{
"id": 256,
"name": "Makeup & Fragrances",
"products": []
},
]
My table structure:
categories (there's no product_id column, since it's one to many)
+----+------+
| id | name |
+----+------+
| | |
+----+------+
| | |
+----+------+
| | |
+----+------+
product
+----+------+-------+-------------+
| id | name | price | category_id |
+----+------+-------+-------------+
| | | | |
+----+------+-------+-------------+
| | | | |
+----+------+-------+-------------+
| | | | |
+----+------+-------+-------------+
My category model is declared like this:
public function products()
{
return $this->hasMany(Product::class);
}
and the product model is:
public function category()
{
return $this->belongsTo(Category::class);
}
you are trying to limit the loaded relation, not the query, you can do this using eloquent-eager-limit
install it:
composer require staudenmeir/eloquent-eager-limit:"^1.0"
then in Category Model:
class Category extends Model
{
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
.....
public function products()
{
return $this->hasMany(Product::class, 'product_id');
}
public function lastFiveProducts()
{
return $this->hasMany(Product::class, 'product_id')
->latest()->limit(5);
}
}
and in Product:
class Product extends Model
{
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
......
}
now this query will get the expected results:
return Category::select('id', 'name')->whereIn('id', $categories)->with(['products' => function($query){
$query->limit(5);
}])->get();
or using the new relation:
return Category::select('id', 'name')->whereIn('id', $categories)->with(['lastFiveProducts'])->get();
also note when you use ->with('products:id,name') loading a relation with specific columns, you always should load the foreing key ->with('products:id,name,category_id')

Display data in view from database Laravel

So i have two tables:
orders
id | time | meals_id | vege
1 | 12:00 | 1 | 0
ingredients
id | value | meals_id
1 | cheese| 1
2 | beef | 1
where ingredients id is type of ingredients like meat.
I'd like to display data in my order view, but I have no idea how show value of ingredients.
This is my order model
public function ingredients(){
return $this->hasMany(ingredient::class);
}
ingredient model
public function order(){
return $this->hasMany(order::class);
}
and orderController
public function show(){
$orders = order::where('vege', 0)->get();
return view('home', ['orders' => $orders]);
}
Thanks for any advice.
in order model make a relation with ingredients
public function ingredients()
{
return $this->hasMany('App\Order', 'order_id' ,'id');
}
you must have a field in ingredients order_id
then you can get order with ingredients
$orders = Orders::with('ingredients')->where('vege',0)->get();
return view('home',compact('orders'));
in home view you can easily
foreach($orders as $order){
foreach($order->ingredients as $i){
echo $i->id;
}
}
orderController
public function show(){
$orders = order::where('vege', 0)->get();
return view("home",compact('orders'));
}
home view
foreach($orders as $order){
foreach($order->ingredients as $i){
echo {{ $i->id }};
}
}

How to query a table based on criteria of another table in Laravel?

In my laravel project I have an inventory and a medicine table which the formats are as the following:
Inventory Table
id | medicine_id | expiry_date
-------|-----------------|-------------
1 | 1 | 13-11-2021
2 | 2 | 01-01-2020
3 | 2 | 23-05-2024
Medicine Table
id | name | category
-------|-----------------|-------------
1 | Hemophine | Syringe
2 | andrenalin | Tablet
3 | aspirin | Capsule
The models are set as below:
Inventory Model
class Inventory extends Model
{
public $incrementing = false;
public function medicine(){
return $this->belongsTo('App\Medicine', 'medicine_id');
}
}
Medicine Model
class Medicine extends Model
{
public $incrementing = false;
public function inventory(){
return $this->hasMany('App\Inventory', 'medicine_id');
}
}
For retrieving all the inventories with a specific category such as Syringe, I tried eager loading, but couldn't figure out the flaws. Here is what I did to get all the inventories with a Syringe category, but it didn't work.
public function index()
{
$medicines = Inventory::where('medicine_id'->category, "Syringe")->get();
foreach($medicines as $medicine){
echo $medicine->medicine->name ." ".$medicine->expiry_date;
echo "<br>";
}
}
Now, Is there anyway to get all the inventory items based on their categories they are in? in this case in "Syringe" category?
Your syntax is a bit wrong, in order to load the medicine for each inventory you need to use with and the where function is where('column', value)
So change it to this:
$medicines = Inventory::with([
'medicine' => function($query) {
$query->where('category', "Syringe");
}
])->get();
or even better the other way around:
$medicines = Medicine::with('inventory')->where('category', 'Syringe')->get();

How to combine models and order by model two data in Laravel 5.4

I would like to be able to output leaders in a section by their position in a group. I'm thinking of combining these tables through a pivot table ordered by position from the groups table.
These are the three class I have relationships established
class Leader extends Model
{
public function groups()
{
return $this->belongsToMany('App\Group');
}
}
class Group extends Model
{
public function leaders()
{
return $this->belongsToMany('App\Leader');
}
}
class GroupLeader extends Model
{
// Maybe some function here?
}
I would like to be able to get the groups in the controller and pass them individually kinda like this.
$group1 = Leader::where('group', '=', 'group1_name')->orderBy('position', 'asc');
$group2 = Leader::where('group', '=', 'group2_name')->orderBy('position', 'asc');
return view('page.leadership')->with([
'group1' => $group1,
'group2' => $group2,
]);
Then I would pass the variables to include files which would loop through them in order.
Here is my table structure
leaders
--------
| id
| first_name
| last_name
| deceased
----------
groups
----------
| id
| group
| title
| position
-----------
group_leader
-------------
| id
| group_id
| leader_id
------------
Try it
$groups = Leader::whereIn('group', ['group1_name', 'group2_name'])
->orderBy('position', 'asc')
->groupBy('group', 'id')
->get(['group', 'id']);

Advanced Filters in laravel

In my case I'm working on search training institutes based on institute name,location and course
I have 3 tables
institutes Table
id | institute_name | phone_number
----------------------------------------------
1 | vepsun | 85214542462
----------------------------------------------
2 | infocampus | 52466475544
Locations table
id | institute_id(fk) | location_name
------------------------------------------------
1 | 1 | Banglore
------------------------------------------------
2 | 1 | delhi
courses table
id | institute_id(fk) | course_name
------------------------------------------------
1 | 1 | php
------------------------------------------------
2 | 1 | delhi
I have created relations between 3 tables tables
Institute Model :
public function locations()
{
return $this->hasMany(Location::class);
}
public function courses()
{
return $this->hasMany(Course::class);
}
Course Model:
public function institute()
{
return $this->belongsTo(Institute::class);
}
Location model:
public function institute()
{
return $this->belongsTo(Institute::class);
}
So I have tried below code
public function filter(Request $request)
{
$institute = (new Institute)->newQuery();
// Search for a user based on their institute.
if ($request->has('institute_name')) {
$institute->where('institute_name', $request->input('institute_name'));
}
// Search for a user based on their course_name.
if ($request->has('course_name')) {
$institute->whereHas('courses', function ($query) use ($request) {
$query->where('courses.course_name', $request->input('course_name'));
});
}
// Search for a user based on their course_name.
if ($request->has('location_name')) {
$institute->whereHas('locations', function ($query) use ($request) {
$query->where('locations.location_name', $request->input('location_name'));
});
}
return response()->json($institute->get());
}
From above code i'm able to filter the data but it show only institution table data like below.
[
{
"id": 2,
"institute_name": "qspider",
"institute_contact_number": "9903456789",
"institute_email": "qspider#gmail.com",
"status": "1",
}
]
but what I need is when I do seach with course_name or instute_name I need to fetch data from institues table,courses and locations table. Can anyone help on this, please?
Eager load the relations in your if statements.
// Search for a user based on their course_name.
if ($request->has('course_name')) {
$institute->whereHas('courses', function ($query) use ($request) {
$query->where('courses.course_name', $request->input('course_name'));
})
->with('courses); // <<<<<< add this line
}
// Search for a user based on their course_name.
if ($request->has('location_name')) {
$institute->whereHas('locations', function ($query) use ($request) {
$query->where('locations.location_name', $request->input('location_name'));
})
->with('locations'); // <<<<<<< add this line
}
This will fetch related courses and locations as well.

Resources