laravel eloquent relationship - laravel

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.

Related

Laravel Eloquent - Accessor not working with relations

I have two model Post and PostImage. In my PostImage model I have set accessor that will concat the image URL to image. I am getting my image response but URL is not prefixed.
Here my PostImage model
class PostImage extends Model
{
use HasFactory;
protected $primaryKey = 'post_image_id';
/**
* Get the image
*
* #return \Illuminate\Database\Eloquent\Casts\Attribute
*/
protected function name(): Attribute
{
return Attribute::make(
get: fn ($value) => config('custom.filepath.products.resize128') . $value,
);
}
}
I am calling return Post::with('images')->get() and here is the response -
{
"post_id": 4,
"customer_id": 1,
"title": "a",
"description": "Its a description",
"target_price": 3000,
"date_of_availability": "2023-02-04",
"condition": "abc",
"latitude": "-31.95303000",
"longitude": "115.85360000",
"attributes": "{\"list\":[{\"title\":\"Color\",\"value\":\"Red1\"},{\"title\":\"Frame\",\"value\":\"Metal Frame1\"}]}",
"created_at": "2023-02-06T08:01:42.000000Z",
"updated_at": "2023-02-06T08:01:42.000000Z",
"images": [
{
"post_image_id": 1,
"post_id": 4,
"name": "167567052363e0b3fbc2fe9.jpg",
"created_at": "2023-02-06T08:02:06.000000Z",
"updated_at": "2023-02-06T08:02:06.000000Z"
},
{
"post_image_id": 2,
"post_id": 4,
"name": "167567052663e0b3fe46bf8.jpg",
"created_at": "2023-02-06T08:02:06.000000Z",
"updated_at": "2023-02-06T08:02:06.000000Z"
}
]
}
I was missing use Illuminate\Database\Eloquent\Casts\Attribute;

Nested API Resource in 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,
];
}

change hasManyThrough() relation attribute name through accessor

I have 3 Models
Campaign PK(id)
CampaignMedium FK(campaign_id)
AccountReceivable FK(campaign_medium_id) (has an amount column)
Controller function:
public function all()
{
return Campaign::with(['customer', 'receivedPayments'])->get();
}
In Campaign Model relationships are defined as follows:
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function accountReceivable()
{
return $this->hasManyThrough(AccountReceivable::class, CampaignMedium::class);
}
public function receivedPayments()
{
return $this->accountReceivable()
->selectRaw('sum(account_receivables.amount) as total')
->groupBy('campaign_id');
}
public function getReceivedPaymentsAttribute()
{
if (!array_key_exists('receivedPayments', $this->relations)) {
$this->load('receivedPayments');
}
$relation = $this->getRelation('receivedPayments')->first();
return ($relation) ? $relation->total : 0;
}
Final Output:
{
"data": [
{
"id": 8,
"name": "example",
"image": "campaign/90375849f6c3cc6b0e542a0e3e6295b890375849f6c3cc6b0e542a0e3e6295b8.jpeg",
"amount": 10,
"description": "saddsa",
"start_at": "2019-02-12 00:00:00",
"end_at": "2019-02-12 00:00:00",
"due_at": "2019-02-12 00:00:00",
"status": "active",
"customer": {
"id": 1,
"name": "test",
"email": "info#test.com",
"image": "customer/ec812116705ff3ae85298234fe6c4e97ec812116705ff3ae85298234fe6c4e97.jpeg",
"address": "sample address"
},
"received_payments": [
{
"total": "700",
"laravel_through_key": 8
}
]
},
{
"id": 9,
"name": "example",
"image": "campaign/fff9fadc92a809513dc28134379851aafff9fadc92a809513dc28134379851aa.jpeg",
"amount": 10,
"description": "saddsa",
"start_at": "2019-02-12 00:00:00",
"end_at": "2019-02-12 00:00:00",
"due_at": "2019-02-12 00:00:00",
"status": "active",
"customer": {
"id": 1,
"name": "test",
"email": "info#test.com",
"image": "customer/ec812116705ff3ae85298234fe6c4e97ec812116705ff3ae85298234fe6c4e97.jpeg",
"address": "sample address"
},
"received_payments": []
}
]
}
summary: trying to get the sum of AccountReceivable amount attribute, which is working fine but the getReceivedPaymentsAttribute() isn't working which needs to return the total value only. also can anyone please help me to explain why laravel_through_key is added with received_payments?
I've never tried to use an attribute modifier to modify a relation this way. You are overriding the expected result of receivedPayments(). You might be better off to define a separate attribute like so:
public function getSumReceivedPaymentsAttribute()
{
// ...your code...
}
Now you can access the attribute using $model->sum_received_payments or always preload it using:
// model.php
protected $appends = ['sum_received_payments'];

Eloquent hasmany relationship issue

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

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