Eloquent one to many relationship not working - laravel

I'm stuck for hours with one of those issues where a fresh set of eyes might help. I just can't understand what's missing.
I'm connecting a model called User_ativo and defining two one-to-many relations to models Instituicao and Tipo_Ativo.
My database is simple.
Table user_ativo has columns "tipo_ativo_id" and "instituicao_id". I have a test row where both are set to 1. Both my tables instituicoes and tipo_ativos have only "id" and a string field "nome" (name). Both have a record with id == 1.
User_ativo.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User_ativo extends Model
{
public function tipo(){
return $this->belongsTo('App\Tipo_ativo');
}
public function instituicao(){
return $this->belongsTo('App\Instituicao');
}
}
Instituicao.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Instituicao extends Model
{
protected $table = 'instituicoes';
public function user_ativos(){
return $this->hasMany('App\User_ativo');
}
}
Tipo_ativo.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tipo_ativo extends Model
{
protected $table = 'tipo_ativos';
public function user_ativos(){
return $this->hasMany('App\User_ativo');
}
}
My controller method that fetches the date goes as follow:
public function index()
{
$ativos = User_ativo::with('tipo', 'instituicao')->get();
return view('ativos.index', compact('ativos'));
}
Now here's where it gets interesting, for some reason I can't figure out, when I echo the $ativos variable in my view I get this:
[{"id":1,"user_id":1,"instituicao_id":1,"tipo_ativo_id":1,"tipo":null,"instituicao":{"id":1,"nome":"Banco do Brasil"}}]
So, weirdly my relationship with the Instituicao model works, but the one with Tipo_ativo returns null.
I'm pretty confident someone will point out some dumb and obvious mistake in all of this, but I can't for the life of me understand why one works and the other doesn't since they're pretty much the same thing.

Your relationships names are not according to laravel convention.
Read below function and provide foreign_key and local_key/owner_key to your relationships then it will work
public function belongsTo($related, $foreignKey = null, $ownerKey = null, $relation = null){}
If we do not follow laravel convention while creating relationships then we have to tell it that these are the foreign and local keys that should be used.
Read more here
class User_ativo extends Model{
public function tipo(){
return $this->belongsTo('App\Tipo_ativo','user_ativo_id'); //second parameter is foreign_key_of_User_avito_table_here
}
public function instituicao(){
return $this->belongsTo('App\Instituicao','user_ativo_id'); //second parameter is foreign_key_of_User_avito_table_here
}
}
class Instituicao extends Model
{
protected $table = 'instituicoes';
public function user_ativos(){
return $this->hasMany('App\User_ativo','instituicao_id'); //second parameter is foreign key of Instituicao model
}
}
class Tipo_ativo extends Model
{
protected $table = 'tipo_ativos';
public function user_ativos(){
return $this->hasMany('App\User_ativo','tipo_ativo_id'); //second parameter is foreign key of Tipo_ativo model.
}
}

Related

Laravel model relationship method

I have 3 tables
User (id,name,mail,mobile)
Contest (id,contest_name,contest_description)
Contest_user (id,user_id,contest_id)
I want to write a has many contest user method in the contest model also I need the user details from the method.
Kindly tell me how can I get the desired result.
Model Screenshot
<?php
namespace App\Model\Contest;
use App\Model\Project\ContestUsers;
use Illuminate\Database\Eloquent\Model;
class Contest extends Model
{
protected $table = 'contest';
protected $fillable = ['name','description'];
public $dates = [
'created_at',
'updated_at',
'deleted_at',
];
//I want to get user details from this method
public function project_contest_users()
{
return $this->hasMany(ContestUsers::class, 'contest_id', 'id')->whereNull('deleted_at');
}
}
contest_user is a pivot table for users and contests and should not have a model class.
The nature of the relation between User and Contest is a many to many, so you need to use belongsToMany() relation in both sides
Contest.php
public function users()
{
return $this->belongsToMany(User::class);
}
User.php
public function contests()
{
return $this->belongsToMany(Contest::class);
}
From what you have done, based on my experience, it's already a good thing that you normalize the many to many relationship. But what N69S said is also correct, that pivot table should not have a Model class, so you need to make your own convention to not use the Model class to create/update/delete (read is fine by me) and if you still want to stick to this method, what you need to do now is just defining the relationships for each of the Models.
User.php:
public function contest_user()
{
return $this->hasMany(ContestUser::class);
}
ContestUser.php:
public function user()
{
return $this->belongsTo(User::class);
}
public function contest()
{
return $this->belongsTo(Contest::class);
}
Contest.php:
public function contest_user()
{
return $this->hasMany(ContestUser::class);
}

Laravel exception: Creating default object from empty value

I'm getting this error just by instantiating a Model and setting a property.
$order_datail = new OrderDetail;
$order_detail->quantity = $product['quantity'];
I'm searching for hours for the cause of this problem but can't find it.
The constructor of OrderDetail is executed. table is order_details, but even by setting protected $table = 'order_details', I'm still getting this error. And yes there is a column 'quantity' in this table.
Strange thing is that I've no problem with other models.
$order = new Order;
$order->pickup_date = $request['date'];
$order->pickup_time = $request['pickupTime'];
The above code runs fine.
Model OrderDetail:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class OrderDetail extends Model
{
use SoftDeletes;
public function replaceds()
{
return $this->hasMany('App\Models\Replaced');
}
public function orders()
{
return $this->belongsTo('App\Models\Order');
}
public function products()
{
return $this->hasMany('App\Models\Product');
}
public function collis()
{
return $this->hasMany('App\Models\Colli');
}
}
Anyone that knows what can be the cause of this?
There is a spelling error on $order_datail = new OrderDetail;
Change it to: $order_detail = new OrderDetail;

Cannot establish relationship between two tables in Laravel

I want to create a relation between lising and attribute table in laravel for that i have used following code to establish relationship between them but the data in my view is not coming from both the tables. I'm getting following error:
Call to undefined relationship [adListAttributes] on model
[App\Models\AdListing].
Here listing can have as many attribute associated with and attributes
can be associated to many listings
ad_listings:
id
title
name
date
ad_list_attributes table :
id
listing_id
name
namespace App\Models;
use Eloquent;
use Illuminate\Database\Eloquent\Model;
class AdListAttribute extends Model
{
protected $table = "ad_list_attributes";
public function Listings()
{
return $this->belongsToMany('AdListing', 'id', 'listing_id');
}
}
namespace App\Models;
use Eloquent;
use Illuminate\Database\Eloquent\Model;
class AdListing extends Model
{
protected $table = "ad_listings";
public function Attributes()
{
return $this->belongsToMany('AdListAttribute', 'listing_id', 'id');
}
}
Problem is that you are using belongsToMany in both the models.This will cause a problem.
In AdListAttribute model,
public function listing_information()
{
return $this->belongsTo('App\AdListing', 'id', 'listing_id');
}
In AdListing model,
public function adlisting_attributes()
{
return $this->hasMany('App\AdListAttribute', 'listing_id', 'id');
}
You can get the results using,
$response = AdListing::get();
if($response->adlisting_attributes)
{
foreach($response->adlisting_attributes as $attribute)
{
echo $attribute->name;
}
}
Problem is that ur not calling the relationship with the right name i assume
$listings = AdListing::with('Attributes')->get();
Update :
Try this :
use App\Models\AdListAttribute;
//
return $this->belongsToMany(AdListAttribute::class, 'listing_id', 'id');
Same for other model, then try

How can you use Eloquent to find related values two tables away and in a different database?

I am developing a system that extends an existing ERP system, and so is accessing two databases (both on the same MS SQL Server). I am trying to access items on the "Equipment" model (this is a table in the ERP database) through the "EquipmentInstance" model from the "EquipmentType" model (these two are in the new database). They are related as per this diagram:
The three models are as follows:
EquipmentType
namespace App;
use Illuminate\Database\Eloquent\Model;
class EquipmentType extends Model
{
protected $table = 'dbo.EquipmentType';
protected $connection = 'sqlsrv';
protected $primaryKey = 'EquipmentTypeID';
protected $fillable = [
'TypeName',
'ProductManager'
];
public function EquipmentInstance()
{
return $this->hasMany(EquipmentInstance::class,'EquipmentTypeID', 'EquipmentTypeID');
}
public function Equipment()
{
return $this->hasManyThrough(
Equipment::class,
EquipmentInstance::class,
'TypeID',
'PartNum',
'TypeID',
'PartNum'
);
}
}
EquipmentInstance
namespace App;
use Illuminate\Database\Eloquent\Model;
class EquipmentInstance extends Model
{
protected $table = 'dbo.EquipmentInstance';
protected $primaryKey = 'EquipmentID';
protected $keyType = 'string';
protected $connection = 'sqlsrv';
protected $fillable = [
'EquipmentID',
'EquipmentTypeID',
'PartNum'
];
public function Part()
{
return $this->belongsTo(Part::class,'PartNum','PartNum');
}
public function Equipment()
{
return $this->hasMany(Equipment::class,'PartNum', 'PartNum');
}
public function EquipmentType()
{
return $this->belongsTo(EquipmentType::class); /*,'EquipmentTypeID', 'EquipmentTypeID'*/
}
/* public function Attribute()
{
return $this->belongsTo(Equipment::class,'SerialNumber', 'JobNum');
}
public function TechNote()
{
return $this->belongsTo(Equipment::class,'SerialNumber', 'JobNum');
}*/
}
Equipment
namespace App;
use Illuminate\Database\Eloquent\Model;
class Equipment extends Model
{
protected $table = 'ERP.SerialNo';
public $timestamps = false;
protected $primaryKey = 'SerialNumber';
protected $keyType = 'string';
protected $connection = 'epicor';
public function Part()
{
return $this->belongsTo(Part::class,'PartNum','PartNum');
}
public function Customer()
{
return $this->belongsTo(Customer::class,'CustNum', 'CustNum');
}
public function Equipment()
{
return $this->belongsTo(Equipment::class,'SerialNumber', 'JobNum');
}
public function EquipmentInstance()
{
return $this->belongsTo(EquipmentInstance::class,'PartNum', 'PartNum');
}
}
On the EquipmentType Controller I am trying to get all of the Equipment through the EquipmentInstance so for each EquipmentInstance I can display all of the Equipments.
EquipmentType Controller
public function show(EquipmentType $EquipmentType)
{
$EquipmentInstance = $EquipmentType->EquipmentInstance()
->get();
$Equipments = $EquipmentType->EquipmentInstance()->Equipment()
->get();
return view('EquipmentType.show', compact('EquipmentType', 'EquipmentInstance', 'Equipments'));
}
The error message I get is
"BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::Equipment()"
I believe the issue is that (my understanding is rocky) that Eloquent is trying to write one query to access both databases, which is failing. However I am not sure how to proceed.
Any help would be greatly received.
Richard
Update
I have implemented what gbalduzzi suggested in his answer, which almost worked, and I am sure the issue is with my blade implemtention. I have nested two forloops:
#foreach($EquipmentType->EquipmentInstance as $EquipmentInstance)
#foreach($Equipments as $Equipment)
<tr>
<td>{{$EquipmentInstance->PartNum}} - {{$EquipmentInstance->Part->PartDescription}}</td>
<td>{{$Equipment->SerialNumber}}</td>
<td>{{$Equipment->SNStatus}}</td>
<td>{{--{{$Equipment->Customer->LegalName}}--}}</td>
</tr>
#endforeach
#endforeach
Which is displaying the serial numbers (from the Equipment model) for the first EquipmentInstance only and repeating them for all EquipmentInstanced.
Update 2
I have proven that the issue is with first() in the suggested answer, as if I change this to last() the results change as you would expect (see update 1). So my question now is:
Is there an equivelant of first(), last() which is all() or every()?
The problem is not in your database configuration, but in the way you are calling the relationship. Instead of:
$Equipments = $EquipmentType->EquipmentInstance()->Equipment()
->get();
use:
$Equipments = $EquipmentType->EquipmentInstance->first()->Equipment()
->get();
Long answer
In Eloquent, you can use a relationship in 2 ways:
as a magic field (i.e. $EquipmentType->EquipmentInstance). In this case you get as a result an instance of the model EquipmentInstance (also, if you already queried it, it directly returns the value without executing a new query)
as an eloquent query (i.e. $EquipmentType->EquipmentInstance()). Using it as a function, you don't get the model but a RelationShip instance, that is basically an eloquent query and can be chained with other eloquent methods, such as where, orderBy, ecc
So, if you call $EquipmentType->EquipmentInstance()->Equipment() it throws an error because the eloquent query does NOT have the relationship Equipment().
On the other hand, $EquipmentType->EquipmentInstance->Equipment works because it calls Equipment on the actual model instance, that has the Equipment relationship properly defined.

Call to undefined method Illuminate\Database\Query\Builder::save() on seed

I'm trying to create seeders to my models using seed and factory. My models have relationship one to many. When I run
php artisan db:seed --class=ChildTableSeeder
I get the following error:
In Builder.php line 2461:
Call to undefined method Illuminate\Database\Query\Builder::save()
Independently of the error the data seed is added to the target table.
My table's structure is like follow:
parents
- parentId
- name
- value
childs
- childId
- parentId
- views
- count
And my models:
//Parent.php
<?php
namespace App\Models\Api;
use Illuminate\Database\Eloquent\Model;
class Parent extends Model
{
protected $primaryKey = 'parentId';
public $incrementing = false;
protected $keyType = 'string';
}
//Child.php
<?php
namespace App\Models\Api;
use Illuminate\Database\Eloquent\Model;
class Child extends Model
{
protected $primaryKey = 'childId';
public $incrementing = false;
protected $keyType = 'string';
public function parents()
{
return $this->belongsTo('App\Models\Api\Parent', 'parentId', 'parentId');
}
}
Also see the Seed code
//ParentTableSeeder
factory(App\Models\Api\Child::class, 50)->create()->each(function ($u) {
$u->parents()->save(factory(App\Models\Api\Parent::class)->make());
});
Anyone has an idea what I'm doing wrong? or How to solve this issue?
You need to use associate() function insted of save()
Also parents() relationshiop's definition is wrong
public function parents()
{
return $this->belongsTo('App\Models\Api\Parent', 'parentId', 'childId');
}
Use the associate method instead of save when creating the relationship:
$p = factory(App\Models\Api\Parent::class)->create():
$u->parents()->associate($p);
$u->save();

Resources