The "key" in Laravel eloquent relationship - laravel

I have 2 models: Invoice and InvoiceItems and these models are connected with invoice_id:
Schema::create('invoice_items', function (Blueprint $table) {
$table->bigInteger('invoice_id')->unsigned();
$table->foreign("invoice_id")->references('id')->on('invoices')->onDelete('cascade');
});
Invoice :
class Invoice extends Model
{
protected $fillable = [
'profile_id',
'invoice_number',
....
];
public function invoiceItems()
{
return $this->hasMany('App\InvoiceItem');
}
}
And InvoiceItems
class InvoiceItem extends Model
{
protected $guarded = [];
public function invoice()
{
return $this->belongsTo('App\Invoice');
}
}
When I want to get an invoice with it's invoice items using eloquent, I use the following code:
$invoice = Invoice::with('invoiceItems')->findOrFail($id);
now the output of dd($invoice->toArray()) is:
array:20 [▼
"id" => 14
"profile_id" => 13
"invoice_number" => null
....
"created_at" => "2020-05-05 09:21:46"
"updated_at" => "2020-05-09 12:09:14"
"invoice_items" => array:1 [▼
0 => array:10 [▼
"id" => 9
"invoice_id" => 14
"price" => "10000.00"
"created_at" => "2020-05-05 09:21:46"
"updated_at" => "2020-05-05 09:21:46"
]
]
]
till now everything looks great, but I'm confused! when I want to use $invoice->invoice_items it returns null while it exists in the top dd($invoice->toArray())!
On the other hand when I use $invoice->invoiceItems it works well!
now whats the reason of this difference?

Use $invoice->invoiceItems instead.
you can find it in the relationships attribute I think.
To array executes laravel logic, they choose to include everything as kebab_case to keep it consistent datawise, but I understand your confusion.

Related

laravel how to show one to many data in view (fetch ) in view

hello I'm trying to fetch one to many data in view like post with this feast comment shooed be show in view
iam able to get value in array now i what to show in view
my array controller
public function data($id)
{
$post= User::with(['Comments'=>function($query){
$query->first();
}])->find($id);
dd($post->toArray());
}
array data
array:53 [▼
"id" => 39
"name" => "KUMAR"
"post" => "hello word "
"created_at" => "2022-02-11T02:38:51.000000Z"
"updated_at" => "2022-02-11T10:05:26.000000Z"
"comments" => array:1 [▼
0 => array:13 [▼
"id" => 6
"user_id" => "39"
"comment" => "good post"
"created_at" => "2022-02-11T15:13:51.000000Z"
"updated_at" => "2022-02-11T15:13:51.000000Z"
]
]
]
my view Controller
public function data($id)
{
$post= User::with(['Comments'=>function($query){
$query->first();
}])->find($id);
return view('user.post',compact('post'));
}
So your User model already has this comments relationship
public function comments()
{
return $this->hasMany(Comment::class);
}
You can add this firstComment relatioship
public function firstComment()
{
return $this->hasOne(Comment::class)->oldest(); // or ->latest()
}
Then fetch your User this way
$post = User::with(['firstComment'])->find($id);
dump($post);
dd($post->firstComment);
Try this
public function data($id)
{
$post= User::wherehas('Comments', function($query){
$query->where('user_id',$id);
})->get();
return view('user.post',compact('post'));
}

Unable to register extra fileds in a pivot table using sync function with Laravel

I'm unable to register extra fields in a pivot table:
This my scheme:
Buyer Model:
public function qualities(){
//many-to-many relation
return $this->belongsToMany(Quality::class);
}
Quality Model:
public function qualities(){
//many-to-many relation
return $this->belongsToMany(Quality::class);
}
Product Model:
public function buyers(){
//many-to-many relation
return $this->belongsToMany(Buyer::class);
}
Before of send the data to the sync function, I'm combining the data:
public function store(createBuyerRequest $request){
if($request->validated()){
try{
//Register buyer
$buyer = new Buyer;
$buyer->ruc = $request->ruc;
$buyer->companyName = $request->companyName;
$buyer->contact = $request->contact;
$buyer->address = $request->address;
$buyer->phone = $request->phone;
$buyer->email = $request->email;
$buyer->save();
$arrayQualitiesIds = $request->get('qualitiesProductCheckbox');
//Build arrayMap
$extra = array_map(function($qualityId) use($request){
return ['quality_id' => $qualityId, 'product_id' => $request->product];
}, $arrayQualitiesIds);
// Combine the array
$data = array_combine($arrayQualitiesIds, $extra);
$buyer->qualities()->sync($data);
return redirect()->route('admin.buyers.index')
->with('status_success','Comprador registrado correctamente!');
}catch(Exception $e){
return redirect()->route('admin.buyers.index')
->with('cancel','No se pudo registrar el comprador. '.$e->getMessage());
}
}
}
The output of $data = array_combine($arrayQualitiesIds, $extra) of one example was this:
Output:
1 => array:2 [▼
"quality_id" => "1"
"product_id" => "5"
]
2 => array:2 [▼
"quality_id" => "2"
"product_id" => "5"
]
3 => array:2 [▼
"quality_id" => "3"
"product_id" => "5"
]
The combination was successfully done! however was unable of register the data in the pivot table, only was registered the buyer.
This is view from the form to register a buyer:
Basically a buyer is being registered and selection a product of interest and his qualities.. The business wants register a buyer with his desired product.
The code $buyer->qualities()->sync($data); should register the buyer_id automatically using the relation and fill the pivot table with array combination putted in $data.
Any Idea for fix this problem guys I will appreciate, thanks so much.
Fixed
I just modified the relation inside of the Buyer model:
public function qualities(){
return $this->belongsToMany(Buyer::class, 'product_interested','quality_id', 'product_id','buyer_id')->withTimestamps();;
}
I also needed of add the buyer_id inside of the array_map:
$extra = array_map(function($qualityId) use($request, $buyer){
return ['quality_id' => $qualityId,
'product_id' => $request->product,
'buyer_id' => $buyer->id];
}, $arrayQualitiesIds);
//combine arrays
$data = array_combine($arrayQualitiesIds, $extra);
/*
dd($data);
array:1 [▼
4 => array:3 [▼
"quality_id" => "4"
"product_id" => "6"
"buyer_id" => 19
]
]
*/
$buyer->qualities()->sync($data);
I don't know the reason why $buyer->qualities()->sync($data) not inserted automatically the buyer_id
You have to specify the name of the pivot table in your relation methods like this:
Buyer Model:
public function qualities(){
//many-to-many relation
return $this->belongsToMany(Quality::class, 'product_interested');
}

Laravel belongsto relations get property problem

I have belongsto relation:
class Yetkiliservis extends Model
{
protected $table = 'yetkiliservis';
protected $guarded=[];
public function bolge(){
return $this->belongsTo(Bolgeler::class);
}
}
when I convert the model to array everything is right. It shows relation.
$yetkiliservisler = Yetkiliservis::with('bolge')->get();
dd($yetkiliservisler[0]->toArray());
result :
array:22 [▼
"id" => 1
"vergi_no" => "1"
"yerel_adi" => "1"
"bolge" => array:6 [▼ <------------------------------------
"id" => 1
"bolge_adi" => "İSTANBUL"
"ad_soyad" => "istanbul"
"email" => "istanbul#mail.com"
"created_at" => "2020-04-24 15:53:31"
"updated_at" => "2020-04-24 15:53:31"
]
"yetkili_adi" => "1"
]
But when I try to get by the property it shows null.
$yetkiliservisler = Yetkiliservis::with('bolge')->get();
dd($yetkiliservisler[0]->getAttributes());
result :
array:22 [▼
"id" => 1
"vergi_no" => "1"
"yerel_adi" => "1"
"bolge" => null <--------------------------------
"yetkili_adi" => "1"
]
First you change the raname like this
public function bolges(){
return $this->hasMany(Bolge::class,'yetkiliservi_id','id');
}
After you execute this command
composer dump-autoload
Then first check php artisan tinker; relation is correct??
Then try this
$yetkiliservisler[0]->bolges;
Hope it will helpful for you

Strange Eloquent Behavior: Trying to get property 'name' of non-object while Object exist

I have this function that returns a value in the DB:
public function getMetaValue($key)
I then created a function to read a data in the DB based off of the getMetaValue:
public function getFeatureByMeta($estate, $type)
{
$metaId = (int) $estate->getMetaValue($type);
$feature = Feature::where('id', $metaId)->first();
return $feature->name;
}
If I now return:
$this->getFeatureByMeta($estate, 'stato_immobile')
It throws
Trying to get property 'name' of non-object.
While if I dump-die the same exact thing it dumps the correct result:
dd($this->getFeatureByMeta($estate, 'stato_immobile'));
//Returns "Nuovo / In costruzione" which is the DB data `name` I need
If I take the function getFeatureByMeta and instead of Feature::where('id', $metaId) I hardcode the id value, the above error does not show up and I do get the correct item name:
public function getFeatureByMeta($estate, $type)
{
$feature = Feature::where('id', 54)->first();
return $feature->name;
}
And
public function getFeatureByMeta($estate, $type)
{
$metaId = (int) $estate->getMetaValue($type);
dd($metaId); //Returns 54
}
If I dd($feature) I do get the row I'm talking about:
App\Feature^ {#904
//...
#attributes: array:5 [
"id" => 57
"name" => "Da ristrutturare"
"category" => "stato_immobile"
"created_at" => "2019-09-16 12:15:13"
"updated_at" => "2019-09-16 12:15:13"
]
#original: array:5 [
"id" => 57
"name" => "Da ristrutturare"
"category" => "stato_immobile"
"created_at" => "2019-09-16 12:15:13"
"updated_at" => "2019-09-16 12:15:13"
]
#changes: []
//...
}
What can be causing this?
I made a video to make it more clear: https://streamable.com/5nsq4
For some reason I still don't understand the only solution I found is this:
public function getFeatureByMeta($estate, $type)
{
$feature = Feature::find($estate->getMetaValue($type));
if ($feature) {
return $feature->name;
}
}
Using the if returns the correct name attribute.
If you know why, please comment.

Eloquent $appends acts strangely in laravel 5.3

am simply trying to include a new attribute to be available in the json response but for some reason am also getting the object relation as well.
// user model
protected $guarded = ['id'];
protected $appends = ['role_name'];
protected $hidden = ['remember_token', 'password'];
public function getRoleNameAttribute()
{
return $this->role->type;
}
public function role()
{
return $this->belongsTo(Role::class);
}
// role model
public function users()
{
return $this->hasMany(User::class);
}
when i use dd($user); i get
User {#303
#guarded: array:1 [
0 => "id"
]
#appends: array:1 [
0 => "role_name"
]
#hidden: array:2 [
0 => "remember_token"
1 => "password"
]
#connection: null
#table: null
#primaryKey: "id"
#keyType: "int"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:7 [
"name" => "testing"
"email" => "email#asd.com"
"password" => "$2y$10$fogQXhJZm5eoViM38pge1.BmNxY7IFl515zT83.Ks9Uj26kK9T6Im"
"role_id" => "83eee2e0-8939-48f7-9fbc-1c077e2265e5"
"id" => "a181fb4b-b65a-47b4-9c72-21ea15c6c5a6"
"updated_at" => "2017-01-30 20:23:52"
"created_at" => "2017-01-30 20:23:52"
]
#original: array:7 [
"name" => "testing"
"email" => "email#asd.com"
"password" => "$2y$10$fogQXhJZm5eoViM38pge1.BmNxY7IFl515zT83.Ks9Uj26kK9T6Im"
"role_id" => "83eee2e0-8939-48f7-9fbc-1c077e2265e5"
"id" => "a181fb4b-b65a-47b4-9c72-21ea15c6c5a6"
"updated_at" => "2017-01-30 20:23:52"
"created_at" => "2017-01-30 20:23:52"
]
...
}
and with return response()->json(compact('user')); instead i get
user: {
created_at: "2017-01-30 20:26:12"
email:"email#asd.com"
id:"4b83e031-e8c8-4050-963d-446cb383fb14"
name:"testing"
role:{
created_at:"2016-12-29 10:54:02"
id:"83eee2e0-8939-48f7-9fbc-1c077e2265e5"
type:"user"
updated_at:"2016-12-29 10:54:02"
}
role_id:"83eee2e0-8939-48f7-9fbc-1c077e2265e5"
role_name:"user"
updated_at:"2017-01-30 20:26:12"
}
but what i expect is to only have
user: {
created_at: "2017-01-30 20:26:12"
email:"email#asd.com"
id:"4b83e031-e8c8-4050-963d-446cb383fb14"
name:"testing"
role_id:"83eee2e0-8939-48f7-9fbc-1c077e2265e5"
role_name:"user"
updated_at:"2017-01-30 20:26:12"
}
so am not sure if this is the normal behavior or a bug or maybe am missing something ?
Laravel version 5.3.30
The reason why this is happening is the following
public function getRoleNameAttribute()
{
return $this->role->type;
}
The problem here is the when you say $this->role it will automatically attached the relationship to the model. In order to prevent this, you should simply be able to access the method directly, like $this->role().
public function getRoleNameAttribute()
{
return $this->role()->first()->type;
}

Resources