Laravel's Eloquent pivot object - laravel-4

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'];

Related

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

How to filter collection in laravel?

I return the ExportTemplate model :
$exportTemplates = ExportTemplate::where('user_id', Auth::id())->get();
the result is something like:
[
{
"id": 45,
"name": "hallo",
"user_id": 1,
"deleted_at": null,
"created_at": "2020-02-27 14:12:50",
"updated_at": "2020-02-27 14:12:50",
"ExportTemplateColumns": [
{
"id": 398,
"export_template_id": 45,
"searchable_column_id": 7,
"created_at": "2020-02-27 14:12:50",
"updated_at": "2020-02-27 14:12:50",
"SearchableColumn": {
"id": 7,
"name": "bic",
"type": "string",
"searchable_table_id": 1,*** I need only results with searchable_table_id ==1
"created_at": "2020-02-06 09:11:24",
"updated_at": "2020-02-06 09:11:30",
"label": "BIC"
}
}
]
},
{
"id": 46,
"name": "fol",
(...)
I want to filter this result through Collection Filter to return only :
ExportTemplateColumns->SearchableColumn->searchable_table_id == 1
Models :
class ExportTemplate extends Model
{
protected $appends = ["ExportTemplateColumns"];
public function getExportTemplateColumnsAttribute()
{
return ExportTemplatesColumns::where('export_template_id',$this->id)->get();
}
public function user()
{
return $this->belongsTo(User::class,'id');
}
public function exportTemplatesColumns()
{
return $this->hasMany(ExportTemplatesColumns::class,'export_template_id');
}
}
class ExportTemplatesColumns extends Model
{
protected $appends = ["SearchableColumn"];
public function getSearchableColumnAttribute()
{
return SearchableColumn::find($this->searchable_column_id);
}
public function exportTemplate()
{
return $this->belongsTo(ExportTemplate::class,'id');
}
public function searchableColumn()
{
return $this->belongsTo(SearchableColumn::class,'id');
}
}
try this.
$exportTemplates = ExportTemplate::where('user_id', Auth::id())->get();
$filtered = $exportTemplates->filter(function($d){
return collect($d->ExportTemplateColumns)->filter(function($columns){
return $columns->SearchableColumn->searchable_table_id === 1;
})->count();
});
$filtered->all();

Laravel eloquent get related model as column_name => value

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

Eloquent (kind of) triple relationship

I'm having a hard time finding a simple solution, using Eloquent relationships, I have 3 models:
User
Item
Category
Now a User has many Categories, a Category only has one user. A user has many items, an item as many users. And finally an item has many categories and many categories has many items. The tricky part is that although an item can have many categories, it can only has one category from each user, so the reverse would be the user can only associate one category that he owns to the item.
Also the pivot table between item and user(item_user) has two attributes, boolean is_owner and tinyInt permissions
During my application I always have the user ID
I would like to retrieve the expenses that belong to the user, achieving something like this:
[
{
"id": "1",
"value": "0.40",
"description": "Expense 0",
"category": {
"id": "1",
"name": "Health",
"created_at": {
"date": "2015-04-15 01:33:05",
"timezone_type": 3,
"timezone": "UTC"
},
"update_at": {
"date": "2015-04-15 01:33:05",
"timezone_type": 3,
"timezone": "UTC"
}
},
"users": [
{
"id": "1",
"name": "Fabio",
"email": "fabioantuness#gmail.com",
"permissions": {
"expense_id": "1",
"user_id": "1",
"is_owner": "1",
"permissions": "6"
}
}
]
},
{
"id": "2",
"value": "12.40",
"description": "Expense 1",
"category": {
"id": "1",
"name": "Health",
"created_at": {
"date": "2015-04-15 01:33:05",
"timezone_type": 3,
"timezone": "UTC"
},
"update_at": {
"date": "2015-04-15 01:33:05",
"timezone_type": 3,
"timezone": "UTC"
}
},
"users": [
{
"id": "1",
"name": "Fabio",
"email": "fabioantuness#gmail.com",
"permissions": {
"expense_id": "2",
"user_id": "1",
"is_owner": "1",
"permissions": "6"
}
}
]
}
]
Item model:
class Item extends Model {
protected $fillable = ['category_id', 'value', 'description'];
public function users()
{
return $this->belongsToMany('App\User')->withPivot('is_owner', 'permissions');
}
public function categories()
{
return $this->belongsToMany('App\Category');
}
}
User model:
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
protected $table = 'users';
protected $fillable = ['name', 'email', 'password'];
protected $hidden = ['password', 'remember_token'];
public function categories()
{
return $this->hasMany('App\Category');
}
public function items()
{
return $this->belongsToMany('App\Item')->withPivot('is_owner', 'permissions');
}
public function tokens()
{
return $this->hasMany('App\Token');
}
}
Category model:
class Category extends Model {
protected $fillable = ['name'];
public function user(){
return $this->belongsTo('App\User');
}
public function items()
{
return $this->belongsToMany('App\Item');
}
}
Schematizing the question here on stackoverflow helped me get to the solution, here's the query:
User::expenses()->with(
[
'users',
'categories' => function ($query) use ($userId)
{
$query->where('user_id', $userId);
}
]
)->get()->all();
If anyone has a better solution feel free to share it

Transform Laravel Eloquent result

When I execute this in my Controller
$data = User::with('teams')->find(2);
return response(['data' => $data]);
I get this as result
{
"id": 2,
"country_id": 1,
"first_name": "John",
"last_name": "Doe",
"created_at": "-0001-11-30 00:00:00",
"updated_at": "2015-02-02 23:08:21",
"full_name": "John Doe",
"teams": [
{
"id": 1,
"name": "Helpdesk medewerker",
"description": ""
},
{
"id": 2,
"name": "Retentie",
"description": ""
}
]
}
Im not interested in the full teams data, but only interested in the teamNames of the user.
I've done this by adding this
$data->each(function($user) {
$user->team_names = $user->teams->lists('name');
unset($user->teams);
});
I was wondering if this is the correct way of modifying the Eloquent result.
You can use an attribute accessor for that. Add this to your model:
protected $hidden = ['teams']; // hide teams relation in JSON output
protected $appends = ['team_names']; // add custom attribute to JSON output
public function getTeamNamesAttribute(){
return $this->teams->lists('name');
}
To change hidden and appends dynamically you can use the setter methods:
$data = User::with('teams')->find(2);
$data->setHidden(['teams']);
Filter out the columns you want in your first build.
$data = User::with(['teams' => function($query){
return $query->select('name');
}])->find(2);
Will output:
{
...
"teams": [
{
"name": "Helpdesk medewerker"
},
{
"name": "Retentie"
}
]
}
You can also use the lists method.
$data = User::with(['teams' => function($query){
return $query->lists('name');
}])->find(2);
Will output:
{
...
"teams": ["Helpdesk medewerker", "Retentie"]
}

Resources