Laravel eloquent get related model as column_name => value - laravel

I have a Product table related with Image table, one to many relationship.
How do I get Image records not as array? Instead, return only 1 Image record as column_name: value
This code:
$products = $request->user()->products()->orderBy('id', 'desc')->with(['images' => function($query) {
$query->where('featured', 1)->limit(1);
}])->get();
Is returning data like this :
{
"id": 13,
"name": "Shoes",
"price": "3.00",
"stock": 5,
"pivot": {
"user_id": 7,
"product_id": 13
},
"images": [
{
"id": 5,
"file": "5da9d9b493403.png",
"featured" 1,
"pivot": {
"product_id": 13,
"image_id": 5
}
}
]
}
}
How to make it return like this?
{
"id": 13,
"name": "Shoes",
"price": "3.00",
"stock": 5,
"pivot": {
"user_id": 7,
"product_id": 13
},
"images": "5da9d9b493403.png"
}
}

You can append a custom accessor that gets the first image from the relationship
In the Product model
protected $appends = ['images'];
public function getImagesAttribute()
{
return $this->images()->where('featured', 1)->first()->file;
}
public function images()
{
return $this->hasMany('App\Image');
}
Then just return the query without eager loading
$products = $request->user()->products()->orderBy('id', 'desc')->get();
Hope this helps

In the Product model
protected $appends = ['images'];
public function images()
{
return $this->hasMany('App\Image')->select(['name'])->first();
}
select the name only and return first relation

Related

Laravel How to orderby()->first() in eager loading

I have this query which is working just fine except when i call ->first() function on it, the data from certain relations disappear.
What I am trying to achieve:
I am trying to get the sp_services where price is lowest. The first object (id: 1) in data array has two sp_services, the second object inside data array (id: 13) has only one sp_services. When i do $query->orderBy('sp_services.price', 'DESC')->first(); The object from first one is there but the second one where (id: 6, name: car wash) disappears and there is only empty array.
In the below mentioned JSON I'm only showing the relevant data here. Can anyone please tell me what am i doing wrong here ? and why is it not working. Also is there a better way to achieve desired result.
Query:
$branchesQuery = SpBranch::query();
$branchesQuery->where('status', true);
$branchesQuery->when($request->filled('price'), function($query) use($request) {
return $query->with(['service_provider' => function($query) use($request) {
$query->whereHas('sp_services')
->with(['sp_services' => function($query) use($request) {
$query->orderBy('sp_services.price', 'DESC'); //->first();
}]);
}]);
});
$branches = $branchesQuery->paginate($perPageLimit);
return $branches;
Models:
class SpBranch extends Model
{
public function service_provider()
{
return $this->belongsTo(ServiceProvider::class, 'sp_id');
}
}
class ServiceProvider extends Model
{
public function sp_services()
{
return $this->hasMany(SpService::class, 'sp_id', 'id');
}
}
JSON:
{
"data": [
{
"id": 1,
"sp_id": 1,
"name": "Branch 01",
"status": 1,
"service_provider": {
"id": 1,
"name": "Service Provider 01",
"sp_services": [
{
"id": 3,
"sp_id": 1,
"branch_id": null,
"name": "Service 03",
"price": 50
},
{
"id": 4,
"sp_id": 1,
"branch_id": null,
"name": "Service 04",
"price": 70
}
]
}
},
{
"id": 13,
"sp_id": 5,
"name": "Branch 13",
"status": 1,
"service_provider": {
"id": 5,
"name": "Service Provider 05",
"sp_services": [
{
"id": 6,
"sp_id": 5,
"branch_id": null,
"name": "car wash",
"price": 300
}
]
}
}
]
}
You cannot order or group by a eager loaded table on database, because what WITH method does is that it fires a new query meaning that is not connected to the first one at all, what you can do is you can order or group them in collections meaning after the data is fetch from db you can order them, I think function is called ->sortBy() which will order by the field you want, but it will cost you on performance. If performance is important in your case, you can always use joins to join both tables which will enable you order results directly from database.
class ServiceProvider extends Model
{
public function sp_services()
{
return $this->hasMany(SpService::class, 'sp_id', 'id')->orderBy('price', 'asc');
}
}

Filter Data with Pivot Table Laravel Eloquent

I want to filter users based on their subscription_status which s stored in a pivot table.
I have Three tables users , subscription_packages , subscription_package_user
$user=User::with(['studentDetails','subscriptionsSatus.courses'])
->withPagination($offset,$perPage)
->get()
->sortBy('first_name')->values();
this code return the response is
[
{
"id": 44,
"first_name": "Abcd Test",
"last_name": "Test lastname",
"student_details": null,
"subscriptions_satus": [
{
"id": 1,
"name": "Gold",
"price": 3000,
"user_id": "2"
"pivot": {
"user_id": 44,
"subscription_package_id": 1,
"subscription_status": "on_free_trial",
"expires_on": null,
"id": 9
},
"courses": [
{
"id": 18,
"title": "English Grammar for Class 3",
"price": 400,
"strikethrough_price": null,
"status": "draft",
"user_id": 2,
"image": "http://127.0.0.1:8000/courses/1615702915.png",
"description": null,
"pivot": {
"subscription_package_id": 1,
"course_id": 18,
}
}
]
}
]
}]
i want to return only users who having subscription_status =$filter.
$filter='acive'or 'on_free_trail'
my model is
public function subscriptionsSatus()
{
return $this->belongsToMany(SubscriptionPackage::class)->withTimestamps()->withPivot('subscription_status','expires_on','id');
}
I havetried
$filter=$request->input('filter')??"active";
$user=User::with(['studentDetails','subscriptionsStatus.courses'])
->whereHas('subscriptionsStatus', function($query) use($filter){
$query->wherePivot('subscription_status','=',$filter);
})
->withPagination($offset,$perPage)
->get()
->sortBy('first_name')->values();
But Got error Column not found 'pivot'
You need to use wherePivot along with the orWhere like below:
public function subscriptionsStatus()
{
return $this->belongsToMany(SubscriptionPackage::class)
->withTimestamps()
->withPivot('subscription_status','expires_on','id')
->wherePivot(function($q){
return $q->where('subscription_status','=','active')
->orWhere('subscription_status','=','on_free_trail');
});
}
Update
Or in your controller:
$user=User::with(['studentDetails','subscriptionsStatus.courses'])
->whereHas('subscriptionsStatus', function($query) use($filter){
$query->withPivot('subscription_status')
->wherePivot('subscription_status','=',$filter);
})
->withPagination($offset,$perPage)
->get()
->sortBy('first_name')->values();

Is it possible to apply condition inside the map function of Laravel?

I wanted to apply some condition in foodOrders. Is it possible to apply condition inside map function that acts as where $foodOrder->foodOrders->where('invoice_id',null)->get();
public function getTableList(Request $request){
$skip =$request->skip;
$limit=$request->limit;
$totaltable = Table::get()->count();
$table = Table::skip($skip)->take($limit)->orderBy('id', 'DESC')->get();
$table->map(function($foodOrder){
$foodOrder->foodOrders;
});
}
Below is the output that this query returns. But I only want the data with null invoice_id
{
"success": true,
"message": "Lists of Table.",
"data": [
{
"id": 2,
"table_number": "TN02",
"food_orders": [
{
"id": 16,
"food_items_id": 1,
"table_id": 2,
"invoice_id": null,
"quantity": 2,
"price": "2000.00"
},
{
"id": 17,
"food_items_id": 2,
"table_id": 2,
"invoice_id": null,
"quantity": 3,
"price": "150.00"
}
]
},
{
"id": 1,
"table_number": "TN01",
"created_at": "2020-10-25 10:44:31",
"updated_at": "2020-10-25 10:44:31",
"food_orders": [
{
"id": 14,
"food_items_id": 1,
"table_id": 1,
"invoice_id": 39,
"quantity": 1,
"price": "2000.00"
}
]
}
]
}
Not the best approach, bu this should do the trick
$table->map(function($foodOrder){
$foodOrder->foodOrders=$foodOrder->foodOrders()->where('invoice_id',null)->get();
});
Note the scopes, you need them to apply where condition. And we say = so the further changes are propagated.
I think what you need to use is a filter and not a map. Or am I wrong ?
You can filter out the whitelisted records for the food_orders.
$table->map(function($record){
$record->food_orders = collect($record->food_orders)
->filter(fn($foodOrder) => is_null($foodOrder->invoice_id));
return $record;
});
From the output data you have shown above it seems that the food_orders is a hasMany relation on the model, so it would be easy to filter out the relation when eager loading
Assuming that Table model has a relation defined for food_orders
class Table extends Model
{
public function food_orders()
{
return $this->hasMany(FoodOrder::class);
}
//... rest of the class code
}
You can constrain the related models when eager loading
$table = Table::with([
'food_orders' => fn($query) => $query->whereNull('invoice_id')
])
->skip($skip)
->take($limit)
->orderBy('id', 'desc')
->get();

Laravel hasmany function returns nothing

When i m using has many without select it returns all fields from userTrancastion table
Invoicemodule.php
$invoice = UserInvoiceDetail::with('transaction')
->select('Id','UserId','TotalPrice')
->where('UserId','=',$playerId)
->get();
return $invoice;
UserInvoiceDetail.php
class UserInvoiceDetail extends Model
{
protected $table = 'user_invoice_details';
protected $primaryKey ='Id';
public function transaction()
{
return $this->hasMany(UserTransaction::class, 'InvoiceId');
}
}
Output
"Invoices":
[
{
"Id": 1,
"UserId": 5,
"TotalPrice": 110,
"transaction": [
{
"Id": 1,
"InvoiceId": 1,
"UserId": 5,
"ReferenceTransactionId": null,
"CategoryId": 1,
"ProductId": 140,
"Price": 5,
"Quantity": 5,
"CustomerId": 1,
},
{
"Id": 2,
"InvoiceId": 1,
"UserId": 5,
"ReferenceTransactionId": null,
"CategoryId": 2,
"ProductId": 3,
"Price": 15,
"Quantity": 3,
"CustomerId": 1,
}
]
}
]
But When i m using has many with select it returns nothing userTrancastion table
UserInvoiceDetail.php
class UserInvoiceDetail extends Model
{
protected $table = 'user_invoice_details';
protected $primaryKey ='Id';
public function transaction()
{
return $this->hasMany(UserTransaction::class, 'InvoiceId')->select('user_transactions.Id','user_transactions.ProductId');
}
}
Output
"Invoices": [
{
"Id": 1,
"UserId": 5,
"TotalPrice": 110,
"transaction": []
},
{
"Id": 2,
"UserId": 5,
"TotalPrice": 110,
"transaction": []
}
]
why this is happening, I want to use join in transaction() function, so i need only selective fields.
How can use select with hasmany()?
Thank you in advance.
The relation need to the column that by which it related so add InvoiceId
also, it doesn't need to add user_transactions
public function transaction()
{
return $this->hasMany(UserTransaction::class, 'InvoiceId')->select('Id','ProductId','InvoiceId');
}

Laravel's Eloquent pivot object

I have defined relation in my model:
public function positions() {
return $this->belongsToMany('Position', 'users_positions')->withPivot('season');
}
Is it possible to display objects with pivot in cleaner way?
For Example:
"positions": [
{
"id": 1,
"name": "A",
"pivot": {
"user_id": 1,
"position_id": 1,
"season": 2014
}
}
],
I would like to get:
"positions": [
{
"id": 1,
"name": "A",
"season": 2014
}
],
Use accessor:
public function getSeasonAttribute()
{
return ($this->pivot) ? $this->pivot->season : null;
}
Then you can access it just like other properties:
$position = $someModel->positions->first();
$position->season;
if you also need it in the toArray/toJson output, then use on you model:
protected $appends = ['season'];

Resources