Nested API Resource in Laravel - laravel

In my Favorite Resource, I have this
public function toArray($request)
{
return [
'book_id' => $this->book,
// 'book_id' => BookResource::collection($this->whenLoaded('book_id')),
'user_id' => $this->user_id,
];
}
But when I send a request to my endpoint
{
"book_id": {
"id": 2,
"name": "fcdsadxa",
"about": "xzxzxZ",
"image_url": "#.png",
"epub_url": "#.epub",
"author_id": 1,
"publisher": "dss",
"year": 1990,
"recommended": 1,
"created_at": "2019-12-07 07:44:51",
"updated_at": "2019-12-07 07:44:51",
"pages": null
},
Is there a way to return the author details not just the ID like below
"id": 1,
"name": "Dragon and Box",
"about": "dss",
"content": null,
"image": "h#.png",
"recommended": 0,
"created_at": "2019-12-07T07:44:51.000000Z",
"updated_at": "2019-12-07T07:44:51.000000Z",
"author": {
"id": 1,
"name": "Odutola Abisoye",
"about": "dsfcds",
"image_url": "#.png",
"created_at": "2019-12-07 07:44:06",
"updated_at": "2019-12-07 07:44:06"
},
As favorite table is a pivot table between User and Book
In my Book Table, I have this
Schema::create('books', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->text('about');
$table->string('image_url');
$table->string('epub_url');
$table->integer('author_id');
$table->string('publisher');
$table->year('year');
$table->boolean('recommended')->default(0);
$table->timestamps();
});
I have done this to set up the relationship
Favorite Model
public function book ()
{
return $this->belongsTo(Book::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
Book Model
public function favorites()
{
return $this->hasMany(Favorite::class);
}
User Model
public function favorites()
{
return $this->hasMany(Favorite::class);
}
This is what my favorite schema looks like
Schema::create('favorites', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('book_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->timestamps();
});

I fixed it by returning my FavoriteResource like this
public function toArray($request)
{
return [
//'book_id' => $this->book,
'book_id' => new BookResource($this->book),
'user_id' => $this->user_id,
];
}

Related

Laravel - how to group by pivot table column

I have a many to many relationship with one extra column in pivot table i.e module_id, i want to eager load the relationship data groupBy('module_id'). I tried couple of thing that didn't work, I successfully managed to get the desired structure but not through the eager loading (right way), i directly called the pivot table model queried the table. The problem is i cannot query pivot table directly becuase i have implemented the repository pattern.
This is how i queries the pivot directly.
$selectedGroups = RoleGroup::select('role_id', 'module_id', 'group_id')->where('role_id', $role->id)->get()->groupBy('module_id');
Migration:
Schema::create('role_groups', function (Blueprint $table)
{
$table->id();
$table->unsignedBigInteger('role_id');
$table->unsignedBigInteger('module_id');
$table->unsignedBigInteger('group_id');
$table->timestamps();
$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
$table->foreign('group_id')->references('id')->on('groups')->onDelete('cascade');
});
Role Model:
public function groups()
{
return $this->belongsToMany(Group::class, 'role_groups')->withPivot('module_id')->withTimestamps();
}
Group Model:
public function roles()
{
return $this->belongsToMany(Role::class, 'role_groups')->withPivot('module_id')->withTimestamps();
}
Desired Structre:
The keys are module_id and the values inside are group_id
{
"1": [
1
],
"2": [
1
],
"3": [
1
],
"4": [
1
],
"5": [
1,
2,
3,
4
]
}
What i got:
{
"1": [
{
"role_id": 1,
"module_id": 1,
"group_id": 1
},
{
"role_id": 1,
"module_id": 1,
"group_id": 3
}
],
"2": [
{
"role_id": 1,
"module_id": 2,
"group_id": 1
},
{
"role_id": 1,
"module_id": 2,
"group_id": 3
}
],
"3": [
{
"role_id": 1,
"module_id": 3,
"group_id": 1
}
],
"5": [
{
"role_id": 1,
"module_id": 5,
"group_id": 1
}
]
}
You may achieve this by grouping by multiple columns. i.e:
RoleGroup::query()
->select("module_id", "group_id")
->where("role_id", $role->id)
->groupBy("module_id", "group_id")
->get()
->reduce(
function (array $carry, Model $item) {
$carry[$item->module_id][] = $item->group_id;
return $carry;
}
, []);
References:
reduce()
groupBy()

laravel eloquent with in with select return null

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

Laravel access value from others object

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.

laravel eloquent relationship

I have two tables
products:id, code,details,created_at
price_revision:id,product_id,revised_price,user,remark,created_at,updated_at
i want to produce following json:
{
"accessory_price":{[
"date":"2015-03-01",
"products":
{[ "product_id":1, "product_name":"test accessory 1", "revised_price":50.00, "user":"samyak", "remarks":"n/a" ], [ "product_id":2, "product_name":"test accessory 2", "revised_price":60.00, "user":"samyak", "remarks":"n/a" ], [ "product_id":3, "product_name":"test accessory 3", "revised_price":70.00, "user":"samyak", "remarks":"n/a" ]}
],
[
"updated_at":"2015-02-01",
"products":
{[ "product_id":1, "product_name":"test accessory 1", "revised_price":40.00, "user":"sam", "remarks":"n/a" ], [ "product_id":2, "product_name":"test accessory 2", "revised_price":50.00, "user":"sam", "remarks":"n/a" ], [ "product_id":3, "product_name":"test accessory 3", "revised_price":60.00, "user":"sam", "remarks":"n/a" ]}
]
]}
I have made model like this:
ProductModel
public function productpricerevision(){
return $this->hasMany('Modules\Quotes\Entities\ProductPriceRevision','product_id');
}
Repository code
public function getProductPrice(){
$productprice=ProductModel::with('productpricerevision')->get();
$data=array('accessory_price'=>$productprice);
return $data;
}
But with this code I get
{
"product_price": [
{
"id": 1,
"code": "G4007",
"detail": "Flyscreen Gasket -4007",
"created_at": "2014-07-11 13:53:02",
"productprice": [
{
"id": 1,
"product_id": 1,
"revised_price": 78,
"user": "sam",
"remark": "test",
"created_at": "2016-03-30 00:00:00",
"updated_at": "2016-03-30 00:00:00"
}
]
},
{
"id": 2,
"code": "CZBR-100S",
"detail": "Single Bearing Roller BR-100-S",
"created_date": "2014-07-11 13:57:15",
"productprice": [
{
"id": 4,
"product_id": 2,
"revised_price": null,
"user": sam,
"remark": null,
"created_at": "2016-03-30 00:00:00",
"updated_at": "2016-03-30 00:00:00"
}
]
},
Product Migration
class CreateProductsTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('products', function(Blueprint $table)
{
$table->integer('id');
$table->string('code', 25);
$table->text('detail', 65535)->nullable();
$table->timestamp('created_date')->default(DB::raw('CURRENT_TIMESTAMP'));
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('products');
}
}
price_revision
public function up()
{
Schema::create('product_price_revision', function(Blueprint $table)
{
$table->increments('id');
$table->integer('product_id');
$table->double('revised_price')->nullable();
$table->string('user')->nullable();
$table->text('remark')->nullable();
$table->foreign('product_id')->references('id')->on('products')->onDelete('CASCADE')->onUpdate('CASCADE');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('product_price_revision');
}
I have tried several other methods too but at the end i got lost. Any help is appreciated.

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

Resources