How to remove pivot keyword from json using laravel? - php

I am trying to fetch data from games table which has pivot table user_games. Below code if works fine for me
$UserGames = User::with(['games' => function ($query){
$query->withPivot('highscore','level');
}])->find(request()->user()->id);
I am getting following json response
{
"data": [
{
"id": 2,
"name": "culpa",
"type_id": 3,
"created_at": "2018-10-30 11:23:27",
"updated_at": "2018-10-30 11:23:27",
"pivot": {
"user_id": 2,
"game_id": 2,
"highscore": 702,
"level": 3
}
}
]
}
But I wanted to remove pivot keyword from above json and pull pivot detail into root as like below my desire response
{
"data": [
{
"id": 2,
"name": "culpa",
"type_id": 3,
"created_at": "2018-10-30 11:23:27",
"updated_at": "2018-10-30 11:23:27",
"user_id": 2,
"highscore": 702,
"level": 3
}
]
}
Can someone kindly guide me how to fix the issue. I would appreciate. Thank you so much

You can utilise hidden and appends on the pivot model to re-structure the returned data.
class PivotModel extends model
{
protected $hidden = ['pivot'];
protected $appends = ['user_id'];
public function getUserIdAttribute()
{
return $this->pivot->user_id;
}
}
Reference for hidden
Reference for appends

You can convert the json into an array than reconvert it to json.
$UserGames = User::with(['games' => function ($query){
$query->withPivot('highscore','level');
}])->find(request()->user()->id);
$UserGames = json_decode($UserGames, true);
$pivot = $UserGames['data'][0]['pivot'];
unset($UserGames['data'][0]['pivot']);
$UserGames = json_encode(array_merge($UserGames[0], $pivot));

You can override the User model's jsonSerialize method which is called in the toJson method, this is the initial method body:
public function jsonSerialize()
{
return $this->toArray();
}
And you can do something like this:
public function jsonSerialize()
{
$attrs = $this->toArray();
if (isset($attrs['pivot'])) {
$attrs = array_merge($attrs, $attrs['pivot']);
unset($attrs['pivot']);
}
return $attrs;
}

Related

Laravel 8 Multiple Table Relationship

This is a long post, sorry in advance.
I have a couple of questions regarding the diagram below.
How do I create a relationship for these tables? (tried "belongsToMany" and "hasMany")
Should I use Eloquent or Query Builder to get desired result? (image is attached below for desired result)
Is "client_order_items" a pivot table?
How can you distinguish a pivot table? Is it because the table has multiple
foreign keys?
How can I access "images" table from "Manufacturer" model? Can "hasOneThrough / hasManyThrough" achieve this?
Is the desired result achievable purely using Eloquent or DB Query?
//sample:
Manufacturers::find(2)->client_order_items->cars->images->car_image
I tried considering "client_order_items" as a pivot table then making relationships using "belongsToMany" in "Manufacturer", "Car" and "ClientOrder" models.
// App\Model\Manufacturer.php
public function client_orders() {
return $this->belongsToMany(ClientOrder::class,
"client_order_items", "manufacturer_id", "client_order_id")
->withPivot('id', 'quantity', 'car_id');;
}
public function cars() {
return $this->belongsToMany(Car::class,
"client_order_items", "manufacturer_id", "car_id");
}
// App\Model\Car.php
public function client_orders() {
return $this->belongsToMany(ClientOrder::class,
"client_order_items", "car_id", "client_order_id");
}
public function manufacturers() {
return $this->belongsToMany(Manufacturer::class,
"client_order_items", "car_id", "manufacturer_id");
}
// App\Model\ClientOrder.php
public function cars() {
return $this->belongsToMany(Manufacturer::class,
"client_order_items", "client_order_id", "car_id");
}
public function manufacturers() {
return $this->belongsToMany(Manufacturer::class,
"client_order_items", "client_order_id", "manufacturer_id");
}
I also tried "hasMany" relationship:
// App\Model\Manufacturer.php
public function client_order_items() {
return $this->hasMany(ClientOrderItems::class);
}
// App\Model\Cars.php
public function client_order_items() {
return $this->hasMany(ClientOrderItems::class);
}
// App\Model\ClientOrder.php
public function client_order_items() {
return $this->hasMany(ClientOrderItems::class);
}
// App\Model\ClientOrderItems.php
public function car() {
return $this->belongsTo(Car::class);
}
public function manufacturer() {
return $this->belongsTo(Manufacturer::class);
}
public function client_order() {
return $this->belongsTo(ClientOrder::class);
}
My goal is to get the result if i did something like this:
// Manufacturer::find(2)->client_orders
// Desired Result:
[
{
"client_order_id": 88062,
"first_name": "Clark",
"last_name": "Kent",
"order_items": [
{
"client_order_item_id": 37394,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
}
]
},
{
"client_order_id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"order_items": [
{
"client_order_item_id": 79913,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
},
{
"client_order_item_id": 84743,
"quantity": 1,
"car_id": 95,
"image": "path_img2"
}
]
}
]
But the result I'm currently getting (with "belongsToMany") is:
// Manufacturer::find(2)->client_orders
// Current Result:
[
{
"id": 88062,
"first_name": "Clark",
"last_name": "Kent",
"pivot": {
"manufacturer_id": 2,
"client_order_id": 88062,
"id": 37394,
"quantity": 1,
"car_id": 68
}
},
{
"id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"pivot": {
"manufacturer_id": 2,
"client_order_id": 60978,
"id": 79913,
"quantity": 1,
"car_id": 68
}
},
{
"id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"pivot": {
"manufacturer_id": 2,
"client_order_id": 60978,
"id": 84743,
"quantity": 1,
"car_id": 95
}
}
]
Sorry again for the long post.
Thank you in advance.
After experimenting and reading for couple of hours, I was able to get the result I want.
Making the relationships:
Manufacturer model has "belongsToMany" relationship with "ClientOrder"
// App\Model\Manufacturer
public function client_orders() {
return $this->belongsToMany(ClientOrder::class, 'client_order_items', 'manufacturer_id', 'client_order_id');
}
"Car" and "Image" model has "hasMany" relationship. This will give us access to "Image" model from "ClientOrderItems" model.
// App\Models\Car
public function image() {
return $this->belongsTo(Image::class);
}
// App\Models\Image
public function cars() {
return $this->hasMany(Car::class);
}
Creating Accessors to Models
In "ClientOrder" model, create an accessor for the "order_items" key. This will fetch rows from "OrderLineItems" that are related to the "manufacturer_id" and "client_order_id".
// App\Models\ClientOrder
protected $appends = ["order_items"];
public function getOrderItemsAttribute() {
$items = ClientOrderItems::where("manufacturer_id", '=', $this->pivot->manufacturer_id)
->where("client_order_id","=",$this->pivot->client_order_id)
->select(["id as client_order_item_id","car_id","quantity"])
->get();
return $items;
}
In "ClientOrderItems" pivot model, create an accessor for the "image".
// App\Models\ClientOrderItems
protected $appends = ["image"];
public function getImageAttribute() {
return Car::find($this->car_id)->image->car_image;
}
The result of the 2 codes above looks something like this:
[
{
"client_order_item_id": 79913,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
},
{
"client_order_item_id": 84743,
"quantity": 1,
"car_id": 95,
"image": "path_img2"
}
]
More on Accessors & Mutators:
https://laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators
Retrieving Records
To get the "client orders" that are related to manufacturer_id, use:
/// App\Http\Controllers\ManufacturerController;
public function index() {
$client_order = Manufacturer::find($manufacturer_id)->client_orders->unique("id")->values();
}
Above code will only fetch unique rows from "client_orders" table. Appending the related "order_items" for each row with the help of accessors.
[
{
"client_order_id": 88062,
"first_name": "Clark",
"last_name": "Kent",
"order_items": [
{
"client_order_item_id": 37394,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
}
]
},
{
"client_order_id": 60978,
"first_name": "Bruce",
"last_name": "Wayne",
"order_items": [
{
"client_order_item_id": 79913,
"quantity": 1,
"car_id": 68,
"image": "path_img1"
},
{
"client_order_item_id": 84743,
"quantity": 1,
"car_id": 95,
"image": "path_img2"
}
]
}
]

Appended one accessor but resource has more than one, how is this possible? - Laravel

I am trying to use an accessor on a model to return the status whether a relationship exists.
My User model:
class User {
protected $appends = ['has_profile'];
public function profile()
{
return $this->hasOne(Profile::class)
}
public function getHasProfileAttribute()
{
$exists = $this->profile;
if($exists){
return 1;
}
else{
return 0;
}
}
}
The problem is when the User model is loaded via User::find(1)->get();, the profile property is also loaded into JSON resource whereas, I only want the has_profile attribute in my JSON return. How should I query the relationship existence without loading it, or should I unload the relationship?
What I Get
"data": {
"id": 270,
"name": "John Doe",
"mobile_number": "01234567890",
"created_at": "2021-08-19T06:55:33.000000Z",
"updated_at": "2021-08-19T06:55:33.000000Z",
"deleted_at": null,
"has_profile": 1,
"profile": {
"id": 1,
"details": "Details"
}
}
What I want
"data": {
"id": 270,
"name": "John Doe"
"mobile_number": "01234567890",
"created_at": "2021-08-19T06:55:33.000000Z",
"updated_at": "2021-08-19T06:55:33.000000Z",
"deleted_at": null,
"has_profile": 1
}
Updated Solution
The problem was $this->profile which led to the profile relation being attached. When used as $this->profile()->get(); or $this->profile()->first(); it works as expected.
You can use unset to remove the attribute profile.
public function getHasProfileAttribute()
{
$exists = $this->profile;
unset($this->profile);
if($exists){
return 1;
}
else{
return 0;
}
}
You can use the except() method from the documentation
User::find(1)->get()->except('profile');
Maybe you have to change order i can't test right now but it's the idea

Laravel 7.0 pagination not working in method chain

Here i am using method chaining on Laravel Eloquent model (User) with pagination,but after calling method each pagination stop working.
Is this behaviour expected or i am missing something. there noting mentioned about this on official docs.
Works fine
User::paginate(10)
->appends(request()->all());
Output
{
"data": [
{
"id": 1,
"email": "user#email.com",
},
{
"id": 2,
"email": "two#email.com",
},
],
"current_page": 1,
"first_page_url": "//localhost/users?page=1",
"last_page": 5,
"last_page_url": "//localhost/users?page=5",
"next_page_url": "//localhost/users?page=2",
"path": "//localhost/users",
"per_page": 10,
"prev_page_url": null,
"total": 50
}
But problem arrives when i call each() method on it
Not working
User::paginate(10)
->appends(request()->all())
->each(function ($user) {
$user['someAttribute'] = 'value';
return $user;
})
Output (pagination not working)
plain simple result only query records. (Omitted pagination info)
[
{
"id": 1,
"email": "user#email.com",
},
{
"id": 2,
"email": "two#email.com",
},
]
I don't think you can retrieve the pagination properties after altering the $items. You'd have to convert the altered data into the LengthAwarePaginator object manually.
$users = User::paginate(15);
$alteredUsers = $users->getCollection()
->each(function($user) {
$user['someAttribute'] = 'value';
return $user;
});
$newPaginatedUsers = new \Illuminate\Pagination\LengthAwarePaginator(
$alteredUsers,
$users->total(),
$users->perPage(),
$users->currentPage(),
[
'path' => \Request::URL(), // optional
]
)->appends(request()->all());
You can look at the source here and have a better idea of how to build the object.
Create an accessor:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function getSomeAttributeAttribute()
{
return 'value';
}
}
$users = User::paginate(10)->appends(request()->all());
https://laravel.com/docs/8.x/eloquent-mutators#defining-an-accessor
https://laravel.com/docs/8.x/eloquent-serialization#appending-values-to-json

laravel eloquent ->with not working with one to one

now i have this method inside my Product model
public static function product_lines($request)
{
$keyword = Helper::clean_keyword($request['keyword']);
$data = Product::where
('number','like','%'.$keyword.'%')->
orWhere('name','like','%'.$keyword.'%')->
with('get_unit_relations')-> // this is one to many
limit(30)->
get();
return $data;
}
and this is the get_unit_relations
public function get_unit_relations()
{
return $this->hasMany('App\Models\Product_unit','product_id','id');
}
like this its working and its return data without any problem ..
{
"id": 1,
"number": "1",
"name": "test",
"foreign_name": null,
"get_unit_relations": [
{
"id": 3,
"unit_id": 2,
"product_id": 1,
"barcode": "455",
"smallest_unit_relation": 12,
"price": 12,
"cost": null,
"created_by": null,
"deleted_by": null,
"created_at": "2020-05-17T21:46:26.000000Z",
"updated_at": "2020-05-17T21:46:26.000000Z",
"deleted_at": null
}
]
}
but if i change the code like this ..
public static function product_lines($request)
{
$keyword = Helper::clean_keyword($request['keyword']);
$data = Product::where
('number','like','%'.$keyword.'%')->
orWhere('name','like','%'.$keyword.'%')->
with('get_smallest_unit_id')-> // this is one to one
limit(30)->
get();
return $data;
}
and this is the get_smallest_unit_id
public function get_smallest_unit_id()
{
return $this->hasOne('App\Models\Unit','id','smallest_unit_id');
}
im getting null in return like this ..
{
"id": 1,
"number": "1",
"name": "test",
"foreign_name": null,
"get_smallest_unit_id": null // it always return null in any one to one relaiton ..
}
how can i use ->with() method with one to one relation
thanks

How to access a nested field in json with Laravel?

Hello I need to access to a nested field within a json file. I am using Laravel 5 and I have this in controller:
public function getLanguages($id){
$user=User::find($id);
if (!$user)
{
return response()->json(['errors'=>array(['code'=>404,'message'=>'No se encuentra un usuario con ese código.'])],404);
}
return Response::make(json_encode($user->languages), 200)->header('Content-Type', 'application/json');
}
This is the output:
[
{
"id": 1,
"name": "Español",
"pivot": {
"id_user": 1,
"id_language": 1
}
},
{
"id": 2,
"name": "Inglés",
"pivot": {
"id_user": 1,
"id_language": 2
}
},
{
"id": 3,
"name": "Alemán",
"pivot": {
"id_user": 1,
"id_language": 3
}
}
]
I want to access to the name of languages that a user has, how can I do that? This is a many to many relationship between User and Language, is better access to the languages trough the User model? or access from the pivot table?
Thanks.
Try This
$user = User::find($id)->languages->toArray();
$languages = array_column($user, 'name');
return Response::make(json_encode($languages), 200)->header('Content-Type', 'application/json');
Since $user->languages is an array containing the languages, you could use array_map, e.g.
function extract_name($el) {
return $el['name'];
}
$names = array_map('extract_name', $user->languages);

Categories