I want to get relationship data into json using Resource in laravel 5.6
When I query, I get response.data.created_by as an object. (first data marked in box) (I need this kind of functionality using API Resources)
But with API Resources it is only showing id and not "created_by" object in response.response.data.created_by. (second data marked in box)
*The data difference is marked inside box.
*The data is fetched using eager fetch.
url: http://localhost:8000/api/product/unit
Response:
{
"data": [
{
"id": 1,
"unit": "Meter",
"symbol": "m",
"decimal": 1,
+----------------------------------------------------------------------------------+
|"created_by": { |
| "id": 1, |
| "name": "Admin", |
| "email": "admin#gmail.com", |
| "api_token": "$2y$10$.c7eJGS6x/C8JN9Hd.Qc1OgPUS8txMDuIHjZNBRRlHQVGrYbJcC5u", |
| "created_at": "2018-05-09 15:45:59", |
| "updated_at": "2018-06-08 15:38:41" |
|}, |
+----------------------------------------------------------------------------------+
"updated_by": {
"id": 1,
"name": "Admin",
"email": "admin#gmail.com",
"api_token": "$2y$10$.c7eJGS6x/C8JN9Hd.Qc1OgPUS8txMDuIHjZNBRRlHQVGrYbJcC5u",
"created_at": "2018-05-09 15:45:59",
"updated_at": "2018-06-08 15:38:41"
},
"created_at": "2018-06-19 00:38:54",
"updated_at": "2018-06-19 20:00:16"
}
],
"resource": {
"data": [
{
"id": 1,
"unit": "Meter",
"symbol": "m",
"decimal": 1,
+----------------+
|"createdBy": 1, |
+----------------+
"updatedBy": 1,
"createdAt": {
"date": "2018-06-19 00:38:54.000000",
"timezone_type": 3,
"timezone": "Asia/Kolkata"
},
"updatedAt": {
"date": "2018-06-19 20:00:16.000000",
"timezone_type": 3,
"timezone": "Asia/Kolkata"
}
}
]
}
}
UnitController.php:
namespace App\Http\Controllers\Product;
use App\Models\Product\Unit;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use App\Http\Resources\Product\UnitResourceCollection;
use App\Http\Resources\Product\UnitResource;
use Illuminate\Validation\ValidationException;
class UnitController extends Controller {
public function index()
{
$units = Unit::with(['created_by', 'updated_by'])->get();
+------------------------------------------------------+
|return [ |
| 'data' => $units, |
| 'resource' => new UnitResourceCollection($units) |
|]; |
+------------------------------------------------------+
}
}
Unit Model:
namespace App\Models\Product;
use Illuminate\Database\Eloquent\Model;
class Unit extends Model
{
public function created_by() {
return $this->belongsTo('App\User', 'created_by', 'id');
}
public function updated_by() {
return $this->belongsTo('App\User', 'updated_by', 'id');
}
}
UnitResource.php
<pre>
namespace App\Http\Resources\Product;
use App\Http\Resources\UserResource;
use Illuminate\Http\Resources\Json\JsonResource;
class UnitResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'unit' => $this->unit,
'symbol' => $this->symbol,
'decimal' => $this->decimal,
'createdBy' => $this->created_by,
'updatedBy' => $this->updated_by,
'createdAt' => $this->created_at,
'updatedAt' => $this->updated_at
];
}
}
The problem was in Unit Model: I had to use different method name created_by() than the column name created_by.
After changing following code, it is working:
Unit.php Model:
public function created_by() { -> public function createdby() {
public function updated_by() { -> public function updatedby() {
UnitController.php Controller:
$units = Unit::with(['created_by', 'updated_by'])->get(); -> $units = Unit::with(['createdby', 'updatedby'])->get();
UnitResource.php Resource:
'createdBy' => $this->created_by, -> 'createdBy' =>new UserResource($this->createdby),
'updatedBy' => $this->updated_by, -> 'updatedBy' => new UserResource($this->updatedby),
Related
I am trying to create an API based on the following two Models:
Product.php
<?php
namespace App\Models\Commerce;
use ...
class Product extends Model {
use HasFactory;
use SoftDeletes;
public mixed $id;
protected $fillable = ['user_id', 'title', 'default_variation', 'status'];
/**
+ * #return HasMany
+ */
public function productVariations() : HasMany {
return $this->hasMany('App\Models\Commerce\ProductVariation');
}
public function defaultVariation() : HasOne {
return $this->hasOne('App\Models\Commerce\ProductVariation', 'default_variation');
}
}
ProductVariation.php
<?php
namespace App\Models\Commerce;
use ...
class ProductVariation extends Model {
use HasFactory;
protected $fillable = ['user_id', 'product_id', 'sku', 'title', 'price', 'status'];
public function product() : BelongsTo {
return $this->belongsTo(Product::class);
}
}
I have configured the JSON:API according to the documents, as best I can tell:
routes/api.php
<?php
use ...
JsonApiRoute::server('v2')->prefix('v2')->resources(function ($server) {
$server->resource('products', JsonApiController::class)->readOnly();
$server->resource('product-variations', JsonApiController::class)->readOnly();
});
ProductSchema.php
<?php
// For authentication see ProductPolicy
namespace App\JsonApi\V2\Products;
use ...
class ProductSchema extends Schema
{
public static string $model = Product::class;
public function fields(): array
{
return [
ID::make(),
DateTime::make('createdAt')->sortable()->readOnly(),
DateTime::make('updatedAt')->sortable()->readOnly(),
Str::make('title'),
Number::make('user_id'),
Number::make('defaultVariation'),
HasOne::make('defaultVariation', 'default_variation'),
Boolean::make('status'),
HasMany::make('productVariations')
];
}
public function filters(): array
{
return [
WhereIdIn::make($this),
];
}
public function pagination(): ?Paginator
{
return PagePagination::make();
}
}
ProductVariationSchema.php
<?php
namespace App\JsonApi\V2\ProductVariations;
use ...
class ProductVariationSchema extends Schema
{
public static string $model = ProductVariation::class;
public function fields(): array
{
return [
ID::make(),
DateTime::make('createdAt')->sortable()->readOnly(),
DateTime::make('updatedAt')->sortable()->readOnly(),
Number::make('userId'),
Number::make('productId'),
Str::make('sku'),
Str::make('title'),
Number::make('price'),
Boolean::make('status'),
BelongsTo::make('product')
];
}
public function filters(): array
{
return [
WhereIdIn::make($this),
];
}
public function pagination(): ?Paginator
{
return PagePagination::make();
}
}
With some dummy data in the database, I can access the endpoint /api/v2/products and receive the following:
{
"jsonapi": {
"version": "1.0"
},
"data": [
{
"type": "products",
"id": "3",
"attributes": {
"createdAt": null,
"updatedAt": null,
"title": "foo-product",
"user_id": 1,
"status": 1
},
"relationships": {
"defaultVariation": {
"links": {
"related": "domain/api/v2/products/3/default-variation",
"self": "domain/api/v2/products/3/relationships/default-variation"
}
},
"productVariations": {
"links": {
"related": "domain/api/v2/products/3/product-variations",
"self": "domain/api/v2/products/3/relationships/product-variations"
}
}
},
"links": {
"self": "domain/api/v2/products/3"
}
}
]
}
/api/v2/product-variations
{
"jsonapi": {
"version": "1.0"
},
"data": [
{
"type": "product-variations",
"id": "3",
"attributes": {
"createdAt": null,
"updatedAt": null,
"userId": 1,
"productId": 3,
"sku": "foo-bar",
"title": "foo bar ",
"price": "11.11",
"status": 1
},
"relationships": {
"product": {
"links": {
"related": "domain/api/v2/product-variations/3/product",
"self": "domain/api/v2/product-variations/3/relationships/product"
}
}
},
"links": {
"self": "domain/api/v2/product-variations/3"
}
}
]
}
However, if I try api/v2/products/3/product-variations or /api/v2/products/3/relationships/product-variations I get a 404 error:
{
"jsonapi": {
"version": "1.0"
},
"errors": [
{
"status": "404",
"title": "Not Found"
}
]
}
Additionally, if I run a test I also get a 404 but I do see that the variations are correctly related:
I think that somewhere I have misconfigured something, but this is my first time doing this in Laravel so I might be completely missing a configuration also.
You only set a JsonApiRoute (starting with api) and prefix('v2') meaning api/v2 group. In this group you add 2 more product-variations meaning /api/v2/product-variations and products /api/v2/products. So anything else don't exists and laravel returns 404.
You need to add
$server->resource('products/{id}/product-variations', JsonApiController::class)->readOnly();
for api/v2/products/3/product-variations
and
$server->resource('products/{id}/relationships/product-variations', JsonApiController::class)->readOnly();
for /api/v2/products/3/relationships/product-variations
Also you can add (int $id) in your controller methods to read this id you pass.
I use laravel eloquent with relations, I have a problem about it.
these are my eloquent models;
class Post extends BaseModel
{
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
}
class User extends BaseModel
{
public function userInfo()
{
return $this->hasOne(UserInfo::class,'user_id','id');
}
}
class UserInfo extends BaseModel
{
}
when I use the following code, the user_info is null.
$posts = Post::with(['user' => function ($query) {
$query->with(['userInfo' => function ($query) {
$query->select(['nickname','avatar']);
}]);
}])->paginate(10)
->toArray();
when i request it , the result is
{
"id": 10,
"community_id": 1,
"title": "biaoti",
"desc": null,
"content": "abc",
"user_id": 1,
"user": {
"id": 1,
"mobile_phone": "13800000003",
"user_info": null
}
}
But the following code is normall.
$posts = Post::with(['user' => function ($query) {
$query->with(['userInfo' => function ($query) {
// $query->select(['nickname','avatar']);
}]);
}])->paginate(10)
->toArray();
when i request it ,the result is :
{
"id": 10,
"community_id": 1,
"title": "biaoti",
"desc": null,
"content": "abc",
"user_id": 1,
"user": {
"id": 1,
"mobile_phone": "13800000003",
"user_info": {
"id": 1,
"user_id": 1,
"nickname": "devkang",
"avatar": "",
"birthday": "1989-01-30",
"sex": 1,
"identity": 1,
"region_id": 1
}
}
}
can you help me? I don't know how to use it, I want to select some fields from user_info.
This is happening because you exclude user_id foreign key when you're using select method. To fix it add foreign key to the list:
$query->select(['nickname', 'avatar', 'user_id']);
I have 3 tables :-
available_offers
- id
- date
- time
- from
- to
- user_id
requested_offer
- id
- user_id
- available_offersID
user
- id
- name
- username
- password
- email
Here my routes_bookedController
class routes_bookedController extends Controller
{
public function create()
{
$user = available_offers::with('user')->get();
$booked = requested_routes::with('available_offers', 'user')
->where('user_id', Auth::id())
->get();
return $booked;
return view ('routes_booked.show', compact('booked'));
}
}
Here the result from show.blade.php from routes_bookedController
[
{
"id": 3,
"user_id": 4,
"available_offersID": 3,
"created_at": null,
"updated_at": null,
"available_offers": {
"id": 3,
"date": "2017-08-08",
"time": "14:11:30",
"from": "Sabah",
"to": "Sarawak",
"user_id": 2,
"isBooked": 1,
"created_at": null,
"updated_at": null
},
"user": {
"id": 4,
"name": "admin",
"username": "user1",
"email": "user1#example.com",
"created_at": "2017-08-08 06:15:49",
"updated_at": "2017-08-08 06:15:49"
}
}
]
Is that possible to grab name from available_offers->user->name ?
This is my model :-
requested_routes
class requested_routes extends Model
{
public function available_offers()
{
return $this->belongsTo(available_offers::class, 'available_offersID');
}
public function user()
{
return $this->belongsTo(User::class);
}
}
available_offers
class available_offers extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function requested_routes()
{
return $this->hasMany(requested_routes::class);
}
}
User
public function available_offers()
{
return $this->hasMany(available_offers::class);
}
public function requested_routes()
{
return $this->hasMany(requested_routes::class);
}
Eager load sub model
$booked = requested_routes::with('available_offers', 'available_offers.user', 'user')
->where('user_id', Auth::id())
->get();
Ensure you add available_offers.user as one of the with clauses.
I am building an API with the lumen micro-framework using Eloquent for the database.
When i use this code to get the shoppinglists from a group, everything works
$group = Group::with(['shoppingLists' => function($query) {
}])->get();
It returns the following object
{
"id": "797799c2-6044-4a3a-a3a6-a71fbb17de68",
"name": "'t snackske",
"description": "best group ever",
"user_id": "7e74223a-ea06-46bf-ab1a-abb01b287e32",
"created_at": "2015-08-09 20:06:40",
"updated_at": "2015-08-09 20:06:40",
"shopping_lists": [
{
"id": "2423eb3c-7dab-4672-b382-895788dec6a0",
"name": "shop",
"description": "food",
"user_id": "7e74223a-ea06-46bf-ab1a-abb01b287e32",
"group_id": "797799c2-6044-4a3a-a3a6-a71fbb17de68",
"created_at": "2015-08-09 20:06:40",
"updated_at": "2015-08-09 20:06:40"
}
]
}
And when I check the queries that are logged i get the following queries:
{
"query": "select * from `groups`",
"bindings": [],
"time": 0.31
},
{
"query": "select * from `shopping_lists` where `shopping_lists`.`group_id` in (?)",
"bindings": [
"797799c2-6044-4a3a-a3a6-a71fbb17de68"
],
"time": 0.34
}
But when i try select specific fields for the shoppinglists this query returns no records
The query builder:
$group = Group::with(['shoppingLists' => function($query) {
$query->addSelect('id', 'name', 'description');
}])->get();
The response:
{
"id": "797799c2-6044-4a3a-a3a6-a71fbb17de68",
"name": "Group",
"description": "testgroup",
"user_id": "7e74223a-ea06-46bf-ab1a-abb01b287e32",
"created_at": "2015-08-09 20:06:40",
"updated_at": "2015-08-09 20:06:40",
"shopping_lists": []
}
The queries from the getQueryLog function
{
"query": "select * from `groups`",
"bindings": [],
"time": 0.23
},
{
"query": "select `id`, `name`, `description` from `shopping_lists` where `shopping_lists`.`group_id` in (?)",
"bindings": [
"797799c2-6044-4a3a-a3a6-a71fbb17de68"
],
"time": 0.32
}
When i copy and paste the last query from the query log in mysql i get the correct row. For some reason, eloquent doesn't show the data from the shopping_lists.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Group extends Model
{
protected $increments = false;
protected $fillable = [
'id',
'name',
'description',
'user_id'
];
protected $primaryKey = 'id';
/**
* Get shoppinglists from this group
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function shoppingLists()
{
return $this->hasMany('App\ShoppingList', 'group_id', 'id');
}
}
You may have to add the foreign key column to the addSelect() method for Laravel to do it's magic.
Group::with(['shoppingLists' => function($query) {
$query->addSelect('id', 'group_id', 'name', 'description');
}])->get();
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'];