Eager loading not pulling relation model.
Hi, Im using Laravel 6. Our database was created with Zend so our model is a bit strange; I have to set the primary keys.
// Customer model
protected $table = 'customer';
protected $primaryKey = 'Customer_ID';
/**
* Get all appointments for the customer.
*/
public function appointments()
{
return $this->hasMany('App\Appointment');
}
Then for the appointments
protected $table = 'appointment';
protected $primaryKey = 'Appointment_ID';
/**
* Get the customer assigned to this appointment.
*/
public function customer()
{
return $this->belongsTo('App\Customer');
}
Now, in a controller:
$appointments = App\Appointment::with('customer')->take(5)->get();
return response()->json($appointments, 200);
The array has the appointments but customer is null:
{... Customer_ID: 1234, customer: null}
Any ideas? Thanks
When you create the relationship in the model, you can tell laravel which is the field of the foreign key.
If you do not do it, laravel supposes the foreign key is id, which is not your case.
The definition of the relationship should becomes:
public function customer()
{
return $this->belongsTo('App\Customer', 'Customer_ID');
}
Related
I have two tables. One contains the user and the other contains meetings.
Each meeting belongsTo exact one User.
Meetings
class Meeting extends Model {
protected $table = 'meetings';
protected $primaryKey = 'owner_id';
/**
* A meeting belongs to exact one User
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user(){
return $this->belongsTo(User::class, 'id');
}}
User
class User extends Authenticatable
{
use Notifiable;
protected $table = 'users';
protected $primaryKey = 'id';
/**
* One User can have many Meetings
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function meetings(){
return $this->hasMany(Meeting::class, 'owner_id');
}
I fetch the data with
$meetings = Meeting::with('user')->get();
But somehow i don't get the related user. It just iterates over all users in the database and breaks if no more user is given.
What the heck am I doing wrong? O.o
Let try to change it:
public function user(){
return $this->belongsTo(User::class, 'id');
}
To
public function user(){
return $this->belongsTo(User::class, 'owner_id', 'id');
}
Looking at your Meeting model there are 2 strange things:
protected $primaryKey = 'owner_id';
Why is that? Shouldn't it be id here?
Second thing:
public function user(){
return $this->belongsTo(User::class, 'id');
}
probably here instead of id you should user owner_id.
So to sum up it seems you set wrong keys for primary key and for relationships and probably that's the reason relationship doesn't work as it should.
I'm upgrading to Laravel 5.2 from 4.2 and running into a weird issues where when I'm using Eager Loading on a relationship, it returns null, but I can call it manually.
Here's my parent model:
namespace App\Models\Hours;
class Hours extends Model {
/**
* Model Setup
*/
protected $table = 'leave_hours';
protected $primaryKey = 'leave_id';
public $timestamps = false;
/**
* Relationships
*/
public function hoursStatus()
{
return $this->belongsTo('App\Models\Hours\HoursStatusType', 'leave_status_code');
}
Here's the HoursStatusType model:
<?php
namespace App\Models\Hours;
use Illuminate\Database\Eloquent\Model;
class HoursStatusType extends Model {
/**
* Model Setup
*/
protected $table = 'leave_status_type';
protected $primaryKey = 'leave_status_code';
public $timestamps = false;
/**
* Relationships
*/
public function hours()
{
return $this->hasMany('App\Models\Hours\Hours');
}
}
Basically Hours has PTO requests that has a status (ie. Pending, Approved, etc). HoursStatusType has only 4 rows and it belongs to many of the Hours request.
I'm doing a big request on the Hours like:
$requests = Hours::with('hoursStatus')->get();
foreach($requests as $r){
print_r($r->hoursStatus);
}
When I try to print this out using a foreach loop, the hoursStatus relationship is blank. HOWEVER, when when I call it without the eager loading, it's fine. The only thing I have changed since upgrading from 4.2 (besides adding namespace) is change the hoursStatus relationship to belongsTo from a hasOne. Another couple of posts mentioned that changing it should fix it. Not so much.
Am I missing something? Thanks!
You should add public $incrementing = false; to your models setup, when the PK is not an autoincrementing int.
How to delete relation table's relations on laravel 4.2? For example, I have a table called category which is related to subcategory. So, category id is related to subcategory as foreign key and mapped for cascade delete in my migrations. Now subcategory table has relations with objects table. So subcategory id is related to objects as foreign key and mapped for cascade on delete. Now when I delete category, subcategory is getting deleted which is fine. But since subcategory is getting deleted, even objects too should get deleted right? But it is not. How to solve this?. Below is my code.
Category Model
use Illuminate\Database\Eloquent\SoftDeletingTrait;
class Category extends Eloquent{
use SoftDeletingTrait;
protected $dates = ['deleted_at'];
protected $table = "categories";
public function subcategory(){
return $this->hasMany('Subcategory', 'category_id');
}
public static function boot()
{
parent::boot();
Category::deleting(function($category) {
$category->subcategory()->delete();
});
}
}
SubCategory model
use Illuminate\Database\Eloquent\SoftDeletingTrait;
class Subcategory extends Eloquent{
use SoftDeletingTrait;
protected $dates = ['deleted_at'];
public $timestamps = false;
protected $table = "subcategories";
public function parent(){
return $this->belongsTo('Category', 'category_id');
}
public function objects(){
return $this->hasMany('Object', 'subcategory_id');
}
public static function boot()
{
parent::boot();
Subcategory::deleting(function($subcategory) {
$subcategory->objects()->delete();
});
}
}
You need to call ->delete() on each model directly to trigger associated model events
Category::deleting(function($category) {
foreach($category->subcategory as $subcategory){
$subcategory->delete();
}
});
I have two models, User and Badge. A user can have multiple badges, and a badge can belong to multiple users. (using a pivot table)
Currently I am getting the data I need, but additionally I am getting the pivot table along. How do I exclude this?
Here's the User model:
class User extends Eloquent {
public function badges() {
return $this->belongsToMany('Badge', 'users_badges');
}
}
And the Badge model:
class Badge extends Eloquent {
public function users() {
return $this->belongsToMany('User', 'users_badges');
}
}
Add pivot to your $hidden property's array in your model(s).
class Badge extends Eloquent {
protected $hidden = ['pivot'];
public function users() {
return $this->belongsToMany('User', 'users_badges');
}
}
And same with your User model
class User extends Eloquent {
protected $hidden = ['pivot'];
public function badges() {
return $this->belongsToMany('Badge', 'users_badges');
}
}
Or you can still hide the pivot on demand this way...
$user = User::find(1);
$user->badges->makeHidden('pivot');
$badge = Badge::find(1);
$badge->users->makeHidden('pivot');
Ok so I am trying to have use the Eloquent method "firstOrCreate" within another Eloquent model.
FriendRequest Eloquent
class FriendRequest extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
public $table = 'requests';
protected $guarded = array('id');
protected $softDelete = true;
public function friend() {
return $this->hasOne('User', 'id', 'friend_id');
}
public function user() {
return $this->hasOne('User', 'id', 'user_id');
}
public function accept() {
// FIRST YOU MUST MARK REQUEST AS ACCEPTED
// THEN SOFT DELETE REQUEST SO IT DOESN'T
// SHOW UP AS ACTIVE FRIEND REQUEST
$this->accepted = '1';
$this->save();
// CREATE FRIENDSHIP USER -> REQUESTED
$friend = Friend::firstOrNew(array('user_id' => Auth::user()->id, 'friend_id' => $this->friend_id));
$friend->save();
// CREATE FRIENDSHIP REQUESTED -> USER
$friend2 = Friend::firstOrNew(array('user_id' => $this->friend_id, 'friend_id' => Auth::user()->id));
$friend2->save();
// SOFT DELETE REQUEST BEING MARKED ACCEPTED
$status = $this->delete();
if (!$status):
return false;
else:
return true;
endif;
}
}
I've tried both firstOrCreate and firstOrNew as shown but with both times 'friend_id' and 'user_id' given in the array are set as '0'.
There is no default on the rows or indexes.
Here's the Friend Eloquent Model
class Friend extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
public $table = 'friends';
protected $guarded = array('id');
public function user() {
return $this->hasOne('User', 'id', 'user_id');
}
public function friend() {
return $this->hasOne('User', 'id', 'friend_id');
}
}
The create() method does mass assignment and this is a big security issue, so Laravel has a protection against it. Internally it has guarded = ['*'], so all your columns will be protected against mass assignment. You have some options:
Set the fillable columns of your model:
class User extends Eloquent {
protected $fillable = array('first_name', 'last_name', 'email');
}
Or set only the ones you want to keep guarded:
class User extends Eloquent {
protected $guarded = array('password');
}
You may, at your own risk also do:
class User extends Eloquent {
protected $guarded = array();
}
Also on the difference between the firstorcreate, and firstornew:
The firstOrNew method, like firstOrCreate will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned. Note that the model returned by firstOrNew has not yet been persisted to the database. You will need to call save manually to persist it:
You can also go through the Facade and use the follwing:
class Settings extends Eloquent
{
protected $table = 'settings';
protected $primaryKey = 'name';
public static function get($settingName)
{
return Settings::firstOrCreate(array('name' => $settingName));
}
}
I believe you should put your accept() function in one of your controllers instead of the model. I'm not sure how and where you're calling this function, but I think it's in the wrong place.