I have an app contain many tables :
products table , order table , order_items table.
I made models for all of them as below :
class Product extends Model
{
use HasFactory;
protected $fillable = [
'product_name',
'category_id',
'price',
'sale',
'counter',
'isfavore'
];
public function Order_item()
{
return $this->hasMany('App\Models\Order_item');
}
public function category()
{
return $this->belongsTo('App\Models\Category' ,'category_id');
}
}
class Order extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'status',
];
public function order_item()
{
return $this->hasMany('App\Models\Order_item');
}
public function user()
{
return $this->belongsTo('App\Models\User' ,'user_id');
}
}
class Order_item extends Model
{
use HasFactory;
protected $fillable = [
'order_id',
'product_id',
'quantity',
];
public function order()
{
return $this->belongsTo('App\Models\Order' ,'order_id');
}
public function product()
{
return $this->belongsTo('App\Models\Product' ,'product_id');
}
}
I want to display details like below depend on order_id :
{
"id": 7,
"user_id": 23,
"status": "ordered",
"order_item": [
{
"id": 30,
"order_id": 7,
"product_id": 5,
"quantity": 1,
"product_name" : "banana", //-----------------------want to add from product model
"price" : "2000" //-----------------------want to add from product model
},
{
"id": 31,
"order_id": 7,
"product_id": 1,
"quantity": 1,
"product_name" : "apple",
"price" : "1500"
}
]
}
I create this controller which show same result above without product name and price:
public function get_order($id){
$order=Order::find($id);
$order->order_item;
return $order;
}
Now just I need to add product name and price from product model ,How can I do that?
You have to load the relationships.
Try this:
public function get_order($id){
$order=Order::find($id);
$order_items = Order_item::with('product')->where('order_id',$id)->get();
return $order;
}
I get best answer from #Develope and #danish-khan-I ,just change controller to :
public function get_order($id){
$order=Order::with('order_item.product')->find($id);
return $order;
}
class Product extends Model
{
use HasFactory;
protected $fillable = [
'product_name',
'category_id',
'price',
'sale',
'counter',
'isfavore'
];
public function Order_item()
{
return $this->hasMany('App\Models\Order_item');
}
public function category()
{
return $this->belongsTo('App\Models\Category' ,'category_id');
}
}
class Order extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'status',
];
public function order_item()
{
return $this->hasMany('App\Models\Order_item');
}
public function user()
{
return $this->belongsTo('App\Models\User' ,'user_id');
}
}
class Order_item extends Model
{
use HasFactory;
protected $fillable = [
'order_id',
'product_id',
'quantity',
];
public function order()
{
return $this->belongsTo('App\Models\Order' ,'order_id');
}
public function product()
{
return $this->belongsTo('App\Models\Product' ,'product_id');
}
}
--- CONTROLLER ---
public function get_order($id){
$order=Order::with('order_item.product')->where('id',$id)->first();
}
---- RESPONSE ----
{
"id": 7,
"user_id": 23,
"status": "ordered",
"order_item": [
{
"id": 30,
"order_id": 7,
"product_id": 5,
"quantity": 1,
"product" : {
"product_name" : "banana",
"price" : "2000"
}
},
{
"id": 31,
"order_id": 7,
"product_id": 1,
"quantity": 1,
"product" : {
"product_name" : "banana",
"price" : "2000"
}
}
]
}
Related
I was required to return this json, I am using api resources in Laravel:
{
"data": [
{
"type": "users",
"id": "1",
"attributes": {
"name": "test name",
"lastname": "test lastname"
"projects": 2
},
"relationships": {
"projects": {
"data": [
{
"id": 1,
"type": "projects"
}
]
}
}
}
]
}
A user has a first Project, I am doing this:
Models/User.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class User extends Model
{
use HasFactory;
protected $guarded = ['id'];
public function firstProject()
{
return $this->hasOne(Project::class)->oldest();
}
public function projects()
{
return $this->hasMany(Project::class);
}
}
ProjectCollection.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ProjectCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => $this->collection
];
}
}
ProjectResource.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProjectResource extends JsonResource
{
public function toArray($request)
{
return [
"type" => "projects",
"id" => $this->id
];
}
}
UserCollection.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => $this->collection
];
}
}
UserResource.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
"type" => "users",
"id" => $this->id,
"attributes" => [
"name" => $this->name,
"lastname" => $this->lastname
"projects" => $this->whenCounted('projects')
],
"relationships" => [
"projects" => new ProjectCollection($this->firstProject),
]
];
}
}
UsersController.php
$users = User::with('firstProject')->withCount('projects')->latest()->limit(10)->get();
return new UserCollection($users);
If I do this:
"relationships" => [
"projects" => new ProjectCollection($this->firstProject),
]
I get this error:
Call to undefined method App\Models\Project::mapInto()
But if I change it to this:
"relationships" => [
"projects" => $this->firstProject,
]
It doesn't display errors, but I get this json:
...
...
"relationships": {
"projects":
{
"id": 1,
"type": "projects"
}
}
...
...
The projects is not wrapped in a data attribute y is not displaying the []
What can I do? Thank you.
I just neeed to wrap the $this->firstProject in an array
"relationships" => [
"projects" => new ProjectCollection([$this->firstProject]),
]
and now it is wrapping it as an array in a data attribute despite I have only one item
"relationships": {
"projects": {
"data": [
{
"id": 1,
"type": "projects"
}
]
}
}
This is the behaviour I wanted, now everything is fine
I'm new to Laravel 7. I faced the problem when summing the total and group by id. Actually I able to produce the sum value however I wish to keep other objects at the same time.
Model
class Invoices extends Eloquent {
public function payments()
{
return $this->hasMany('Payments');
}
}
class Payments extends Eloquent {
public function invoices()
{
return $this->belongsTo('Invoices');
}
}
Expected result
"items": [
{
"sale_id": 1,
"item_id": 1,
"code": "9789814820791",
"qty" :1,
"total": "20.00",
},
{
"sale_id": 1,
"item_id": 2,
"code": "9789814820790",
"qty" :1,
"total": "20.00",
},
"total_amount" : 40,
]
Code
$results = Invoices::with([
'payments' => function ($qry) {
$qry->select(['sale_id', app('db')->raw('sum(total) AS total_amount')])->groupBy('sale_id');
}
])
->get();
With the code above, I'm able to get sale_id and total_amount however the other result was missing. I did tried added $qry->select(['sale_id','item_id', 'code', 'qty' 'total']); but it does not work.
How do I return the image list from the Laravel API?
I want to send images from the API as a collection. How can I do it?
I would like to do it using ProductCollection resource if possible.
Thank you from now.
I would like to fetch the file data from this:
{
"data": [
{
"id": 20,
"name": "Cali Howe",
"price": "4.00",
"imageUrl": "C:\\Shop\\shop.api\\public\\img/default.png",
"category_name": "Consequuntur ut.",
"detail": "http://127.0.0.1:8000/api/product/20"
},
{
"id": 19,
"name": "Annie Murazik",
"price": "13.00",
"imageUrl": "C:\\Shop\\shop.api\\public\\img/default.png",
"category_name": "Consequuntur ut.",
"detail": "http://127.0.0.1:8000/api/product/19"
}
],
"links": {
"first": "http://127.0.0.1:8000/api/product?page=1",
"last": "http://127.0.0.1:8000/api/product?page=10",
"prev": null,
"next": "http://127.0.0.1:8000/api/product?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 10,
"path": "http://127.0.0.1:8000/api/product",
"per_page": 2,
"to": 2,
"total": 20
}
}
Product Controller:
public function index()
{
return ProductCollection::collection(Product::orderBy('id', 'DESC')->paginate(2));
}
Product Collection:
class ProductCollection extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'imageUrl' => $this->imagePath('default.png'),
'category_name' => $this->category->name,
'detail' => route('product.show', $this->id),
];
}
}
Product Model:
class Product extends Model
{
protected $guarded = ['id', 'created_at', 'updated_at'];
public function category()
{
return $this->belongsTo(Category::class);
}
public function imagePath($fileName)
{
return public_path('img/' . $fileName);
}
}
Product Migration:
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('category_id');
$table->string('name')->index();
$table->decimal('price')->default(0);
$table->string('image')->nullable();
$table->timestamps();
$table->foreign('category_id')->references('id')
->on('categories')->onDelete('cascade');
});
}
You can convert the image to base64
$imagedata = file_get_contents("/path/to/image.jpg");
$base64 = base64_encode($imagedata);
Edited
class ProductCollection extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'imageUrl' => $this->imagePath('default.png'),
'category_name' => $this->category->name,
'detail' => route('product.show', $this->id),
'base64' => base64_encode(file_get_contents($this->imagePath('default.png')),
];
}
}
For some bizarre reason my Laravel 5.6 app continues to return a User object with all of its relations.
My query in the Api/UserController:
public function show($user_id)
{
return User::with('meta', 'roles')->find($user_id);
}
The response:
{
"id": 1,
"name": "Admin",
"email": "admin#example.com",
"company_id": 1,
"meta": {
"id": 1,
"user_id": 1,
"laptop": 0,
"mobile": 0,
"created_at": "2018-03-07 14:58:41",
"updated_at": "2018-04-06 16:13:10"
},
"roles": [
{
"id": 2,
"name": "admin",
"label": "Admin",
"permissions": null,
"pivot": {
"user_id": 1,
"role_id": 2
}
}
],
"company": {
"id": 1,
"name": "Company",
"active": 1,
"created_at": "2018-04-12 15:06:01",
"updated_at": "2018-05-15 11:20:15",
"is_max_user_limit_reached": true
}
}
The route (inside routes/api.php):
Route::group(['middleware' => 'auth:api'], function () {
Route::resource('/users', 'Api\UserController', ['as' => 'api']);
});
User model:
namespace App\Models;
use App\Models\Role;
class User extends Authenticatable implements HasMedia
{
use HasApiTokens, Notifiable, Billable, HasMediaTrait;
protected $table = 'users';
protected $fillable = ['name', 'email', 'password', 'is_active', 'company_id', 'stripe_id', 'card_brand', 'card_last_four', 'trial_ends_at'];
protected $hidden = ['password', 'remember_token','card_brand', 'card_last_four'];
protected $appends = ['extra', 'is_staff_only', 'first_four_training_sections', 'is_free_tier', 'is_agency_tier', 'is_team_tier', 'is_enterprise_tier'];
public static $rules = [
// create rules
'name' => 'required',
'email' => 'required|email|unique:users'
];
public function meta()
{
return $this->hasOne(UserMeta::class);
}
public function company()
{
return $this->belongsTo(Company::class, 'company_id')->where('active', 1);
}
public function roles()
{
return $this->belongsToMany(Role::class);
}
public function getExtraAttribute()
{
return [
'roles' => [
'cpo' => (int)$this->hasRole('cpo'),
'ap' => (int)$this->hasRole('ap'),
'cao' => (int)$this->hasRole('cao'),
]
];
}
public function getIsStaffOnlyAttribute()
{
if($this->roles->count() == 1 && $this->hasRole('staff')) {
return true;
}
return false;
}
public function getIsFreeTierAttribute()
{
return $this->company->subscription_tier == 0;
}
public function getIsAgencyTierAttribute()
{
return $this->company->subscription_tier == 1;
}
public function getIsTeamTierAttribute()
{
return $this->company->subscription_tier == 2;
}
public function getIsEnterpriseTierAttribute()
{
return $this->company->subscription_tier == 3;
}
public function getFirstFourTrainingSectionsAttribute() {
return UserTrainingSection::where('user_id', $this->id)->orderBy('id')->take(4)->get();
}
}
This is very strange behavior. I am asking for only the roles and meta related data but it's always returning every single relation on the User model.
Even if I try User::find($user_id); it will still return all the relations.
Anyone know what's going on here?
I'm using Laravel 5.6 and PHP 7.2
You can use the $hidden property to remove relationships from the response:
protected $hidden = ['company', ...];
You can also temporarily remove relationships:
$user->addHidden('company');
I have a Product Model that needs to be connected with Processings, that describe how the Product can be manipulated, and Positions, that describe where the Product can be manipulated.
In other words, a Product can be processed into multiple positions.
The "Product Data" should be returned with nested processings into positions, so that, for every Position into the database, a Product can be associated with related Processings, in a scheme similar to the one below:
Products [
product_attributes,
Positions [
position_attributes,
Processings: [
processing_attributes
]
]
]
So, I have created a 3-way Pivot Table with the following code:
Schema::create('product_position_processing', function (Blueprint $table) {
// 3-way pivot
$table->integer('product_id')->unsigned()->index();
$table->foreign('product_id', 'ppp_aid_foreign')->references('id')->on('products')->onDelete('cascade');
$table->integer('position_id')->unsigned()->index();
$table->foreign('position_id', 'ppp_bid_foreign')->references('id')->on('positions')->onDelete('cascade');
$table->integer('processing_id')->unsigned()->index();
$table->foreign('processing_id', 'ppp_cid_foreign')->references('id')->on('processings')->onDelete('cascade');
$table->primary(['product_id', 'position_id', 'processing_id'], 'index-base-combined');
// these attributes define the minimum and maximum order amount based on the product + position + processing combination
$table->integer('minimum_order_amount')->nullable();
$table->integer('maximum_order_amount')->nullable();
$table->timestamps();
});
Then, I have defined the relations between the 3 different models in this way:
Processing Model
class Processing extends Model {
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $guarded = ['id', 'created_at', 'updated_at'];
protected $casts = [
'is_publicly_hidden' => 'boolean'
];
protected $hidden = ['pivot'];
public function products() {
return $this -> belongsToMany ( Product::class, 'product_position_processing', 'processing_id', 'product_id' );
}
public function positions () {
return $this -> belongsToMany ( Position::class, 'product_position_processing', 'processing_id', 'position_id' );
}
...
...
}
Position Model
class Position extends Model {
use SoftDeletes;
protected $dates = ['deleted_at'];
protected $guarded = ['id', 'created_at', 'updated_at'];
protected $hidden = ['pivot'];
public function products() {
return $this->belongsToMany ( Product::class, 'product_position_processing', 'position_id', 'product_id' );
}
public function processings ( ) {
return $this -> belongsToMany ( Processing::class, 'product_position_processing', 'position_id', 'processing_id' );
}
...
...
}
Product Model
class Product extends Model implements SluggableInterface {
use SoftDeletes;
use SluggableTrait;
protected $dates = ['deleted_at'];
protected $guarded = ['id', 'created_at', 'updated_at'];
protected $sluggable = [
'build_from' => 'name',
'save_to' => 'slug',
'include_trashed' => true
];
...
...
public function processings() {
return $this->belongsToMany(Processing::class, 'product_position_processing', 'product_id', 'processing_id');
}
public function positions() {
return $this->belongsToMany(Position::class, 'product_position_processing', 'product_id', 'position_id');
}
...
...
public function scopeWithCompleteData ($query) {
return $query->with([
...
...
'positions' => function($query) {
return $query->with(['processings' => function ( $query ) {
return $query->select('id', 'name')->groupBy('processing_id');
}])->groupBy('position_id');
},
...
...
]);
}
}
Now, the Products are returned in json via the ProductsController that, with the following code, returns a JSON in this format.
Product Getter:
...
...
$products = Product::withCompleteData() -> get();
return $this -> ok ( $products );
Example "ALL Products" #get JSON:
{
"status": "OK",
"data": [
{
"id": 1,
"category_id": 1,
"subcategory_id": 0,
"brand_id": 1,
"sku": "BD615149D6",
...
...
"positions": [
{
"id": 1,
"name": "POS1",
"processings": [
{
"id": 1,
"name": "PROC1",
"pivot": {
"position_id": 1,
"processing_id": 1
}
},
{
"id": 2,
"name": "PROC2",
"pivot": {
"position_id": 1,
"processing_id": 2
}
},
{
"id": 3,
"name": "PROC3",
"pivot": {
"position_id": 1,
"processing_id": 3
}
}
]
},
{
"id": 2,
"name": "POS2",
"created_at": "2016-08-01 07:39:11",
"updated_at": null,
"deleted_at": null,
"processings": []
},
{
"id": 3,
"name": "POS3",
"created_at": "2016-08-01 07:39:11",
"updated_at": null,
"deleted_at": null,
"processings": []
}
]
},
{
"id": 2,
"category_id": 2,
"subcategory_id": 0,
"brand_id": 2,
"sku": "BD615149D6",
...
...
"positions": [
{
"id": 5,
"name": "POS5",
"created_at": "2016-08-01 07:39:11",
"updated_at": null,
"deleted_at": null,
"processings": []
}
]
}
]
}
The problem is, the data returned is not correct. The Query Builder seems to connect the various relationships in a strange way. Unfortunately I'm still not enough proactive in understanding what lies below the magic of the query builder, and don't know how to debug and where to make modifications to the code.
Can anyone help out with this 3-way pivot table with nested objects into the Laravel query builder?