Laravel Eloquent relationship returning null - php

I seem to be having issues with my Eloquent relationships. I have a couple of tables to demonstrate
Schema::create('properties', function (Blueprint $table) {
$table->integer('id')->unsigned()->index();
$table->integer('propertyid')->unsigned()->index();
$table->longText('description')->nullable();
$table->boolean('garden')->nullable();
$table->boolean('parking')->nullable();
});
Schema::create('address', function (Blueprint $table) {
$table->integer('propertyid')->unsigned()->index();
$table->string('name')->nullable();
$table->string('street')->nullable();
$table->foreign('propertyid')
->references('propertyid')
->on('properties')
->onDelete('cascade');
});
Removed a lot of columns to cut down on code. The relationships are pretty straight forward, within Property.php I define the relationship to address, using the foreign key name.
public function address()
{
return $this->hasOne(Address::class, 'propertyid');
}
And then in Address.php I do the inverse
public function property()
{
return $this->belongsTo(Property::class, 'propertyid');
}
When I populate my database, I can go into the address table, click on the propertyid, and it takes me to the correct property, so it seems to be set up correctly. However, in my Controller, if I do
$properties = Property::with('address')->paginate(6);
And I output this using dd, the relations output returns null
#relations: array:6 [
"address" => null
]
Why does this not pick up the relationship?
Thanks

You have to mention localkey as well in hasOne relation.Looks like mapping between two table columns are propertyid not id as per migration
$table->foreign('propertyid')
->references('propertyid')
So realtionship should be
public function address()
{
return $this->hasOne(Address::class, 'propertyid','propertyid');
}
Also need yo change belongsTo relationship as well
public function property()
{
return $this->belongsTo(Property::class, 'propertyid', 'propertyid');
}

Related

Laravel Eloquent where statement returns no attributes

So from my previous post, I was advised to start using Eloquent models, which I did.
My end goal, is to print out specific gifts, that belongs to that specific box.
Migrations:
gift_items:
public function up()
{
Schema::create('gift_items', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->float('unit_price');
$table->integer('units_owned');
});
}
gift_campaigns:
public function up()
{
Schema::create('gift_campaigns', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->foreignId('user_foreignK')->constrained('users');
$table->integer('gift_item_count')->nullable();
$table->string('status');
$table->date('dispatch_date');
$table->date('delivery_date');
});
}
Pivot table:
public function up()
{
Schema::create('campaigns_gifts', function (Blueprint $table) {
$table->foreignId('gift_id')->constrained('gift_items');
$table->foreignId('campaign_id')->constrained('gift_campaigns');
});
}
Controller:
function box($id){
$data = Campaign::with('gifts')->where('id', $id)->get();
return view('DBqueries.boxView', ['data'=>$data]);
}
Error that I receive using this way:
Seems like the updated version is trying to call the gift_campaigns table id, instead of the pivots table campaign_id.
Once again, I need that Request $id would match the pivots table campaign_id, and print out all of the gifts that this specific id holds
First of all as I sense the campaigns_gifts is a pivot table for campaigns and gifts having a Many-to-Many relation. You are doing it completely against the conventions of Laravel.
You generally do not use a Model for pivot table.
You generally do not fetch data from the pivot table directly. Instead use the relation on one of the related Models.
Note: Laravel does allow a Model for a Pivot, and you can query the pivot table directly, just check the documentation.
The correct way:
Pivot
Make a pivot table (that you already have) with column gift_id and campaign_id. i.e., the convention for naming keys as [table_name_singular]_[primary_key_on_table]
Model
One each model, define relationship for the other data as:
Gift.php Model:
public function campaign() {
return $this->belongsToMany(Campaign::class, 'campaign_gift');
}
Campaign.php Model:
public function gifts() {
return $this->belongsToMany(Gift::class,'campaign_gift');
}
since gift have a hasMany relation, the gifts table must contain a foreign key to campaigns table named campaign_id (same as the one on pivot).
Controller
Now in your controller:
function box($id){
$data = Campaign::where('id',$id)->with('gifts')->get();
return view('DBqueries.boxView', ['data'=>$data]);
}
You don't need to tell Laravel which columns, tables etc are you referring to, as long as you follow the conventions, Laravel will magically do things that otherwise would have been much more painful.

How to get foreign keys from laravel model?

is there any way to get the foreign keys from a laravel model?
I've found that you can get the primary key by using the method getKeyName(); but havn't found any solution to get the foreign keys.
For example class Grades has the following relations:
public function student()
{
return $this->belongsTo(Student::class, 'student_id', 'id');
}
public function subject()
{
return $this->belongsTo(Subject::class, 'subject_id', 'id');
}
and the following migration:
Schema::create('grades', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('student_id');
$table->unsignedBigInteger('subject_id');
$table->float('grade', 3, 1);
$table->dateTime('graded_at');
$table->timestamps();
$table->foreign('student_id')
->references('id')
->on('students');
$table->foreign('subject_id')
->references('id')
->on('subjects');
$table->unique(['student_id', 'subject_id']);
});
The desired result would be something like:
$grades= new Grades();
return $grades->getForeignKeys();
// desired result
// [
// student_id,
// subject_id
// ]
Is there any way to get all the foreign keys without being able to alter the model?
Eloquent is a pretty magic ORM, it needs nearly no configuration to sync your database to your models but this freedom is at a cost: it doesn't know your database modelisation.
There is no automatic way of getting foreign keys name from a model. But you can make it work by yourself:
Defining relationship like you did returns a relation object, like BelongsTo. Relationship objects have methods to get foreign keys that you defined like getForeignKeyName
So you can do something like this:
$grade = Grade::findOrFail($id);
$fks = [];
$fks [] = $grade->student()->getForeignKeyName();
$fks [] = $grade->subject()->getForeignKeyName();
Another approach would be to add an attribute in your models that stores the foreign keys you want to use, use it as a single source of truth for your relationship definition too, like this:
class Grades extends Model{
protected $foreignKeys = [
'subject' => 'subject_id',
'student' => 'student_id'
];
public function student()
{
return $this->belongsTo(Student::class, $this->foreignKeys['student'], 'id');
}
public function subject()
{
return $this->belongsTo(Subject::class, $this->foreignKeys['subject'], 'id');
}
public function getForeignKeys(){
return array_values($this->foreignKeys);
}
}

Update parent model with the HasOne child relationship

I have a League model and a Season model their respective migrations and relationships.
League migration and relations
Schema::create('leagues', function (Blueprint $table) {
$table->unsignedBigInteger("id")->primary();
$table->boolean("active");
$table->string("name");
$table->unsignedBigInteger("current_season_id")->nullable();
$table->timestamps();
});
public function current_season()
{
return $this->hasOne(Season::class);
}
Season migration and relations
Schema::create('seasons', function (Blueprint $table) {
$table->unsignedBigInteger("id")->primary();
$table->string("name");
$table->unsignedBigInteger("league_id");
$table->boolean("is_current_season");
$table->timestamps();
});
public function league()
{
return $this->belongsTo(League::class);
}
I have two vars with my models:
$league = League::find(1);
$season = Season::find(10);
With this line, I know automatically league_id in the Season model is filled with the $league->id
$season->league()->associate($league)->save();
I want do the inverse, and fill the current_season_id without doing:
$league->current_season_id = $season->id;
$league->save();
Is it possible?
Following the comments from #M Khalid Junaid, I think it´s better this way:
Remove current_season_id from League model.
Rewrite the current_season relation to this way:
public function current_season()
{
return $this->hasOne(Season::class)->where("is_current_season", true);
}
Now, in this way, I can access the current season of the league in the form: $league->current_season
Thank you.
You do not need $table->unsignedBigInteger("current_season_id")->nullable(); in leagues table, if you are using hasOne relationship, otherwise you need another type of relationship.
I'd strong recommend in seasons table, to use a foreign key declaration in your migration
$table->unsignedBigInteger("league_id");
$table->foreign( 'league_id' )->references( 'id' )->on( 'leagues' );

Laravel: Custom Foreign Key in One-To-Many Relationship Does Not Resolve

There are two Models User and Submission and a User can have any number of submissions in which he is referenced as Author. I have set up the relationship according to the documentation and
the result of hasMany() is working fine. Only the belongsTo() method does not return the expected objects.
Here is the migration of my models:
Schema::create('users', function (Blueprint $table) {
$table->id();
});
Schema::create('submissions', function (Blueprint $table) {
$table->id();
$table->foreignId( 'author' );
$table->foreign( 'author' )->references('id')->on('users');
});
And these are the relationships within my models:
class User extends Authenticatable {
public function submissions() {
return $this->hasMany( 'App\Submission', 'author' );
}
}
class Submission extends Model {
public function author() {
return $this->belongsTo( 'App\User', 'author' );
}
}
Now, in my controller I want to execute this code:
$author = Submission::find(1)->author;
dd($author);
But, instead of the user object, the stored integer value of the author ID is printed. The relationship does not seem to be resolved via the author() method.
On the other hand, when I fetch a user and their submissions, everything works as expected, i.e. the submissions are printed as objects:
$u = User::find(1)->submissions;
dd($u);
But the relation from Submission to User does get resolved properly, when I do not define a custom foreign key with belongsTo and rename the colum to author_id.
The configuration that works is this one:
//migration for Submissions table
Schema::create('submissions', function (Blueprint $table) {
$table->id();
$table->foreignId( 'author_id' );
$table->foreign( 'author_id' )->references('id')->on('users');
});
//within Submission model
public function author() {
return $this->belongsTo( 'App\User' );
}
I have the feeling that I'm missing something. Is there any additional link I have to make? I browsed through the documentation and the web for solutions, but to no success. If there is no other solution, I'll follow with renaming the column. But I'd rather understand the cause of my problem and work with my original design.
you should not name relation functions and fields using the same string.
When you have a column author and a public function author() laravel goes for column content first.
Add '_id' to the column, so you do not need to define referenced field in $this->belongsTo( 'App\User', 'author' );.

One to Many Relationship Laravel cannot display the related data

I have two models called DataKelurahan and RegistrasiPasien and have a one-to-many relationship, but I can't access the relationship.
I have made a form for adding patient and save it to the registrasi_pasiens table and it works well. but when I try to display the relation data, it doesn't work properly.
In the registrasi_pasiens table, I have 1 record with kelurahan_id = 3. Then, I try to access it via php artisan tinker with these command:
$kelurahan = App\Domain\DataKelurahan\Models\DataKelurahan::find(3) works fine and data is exist.
$pasien = App\Domain\RegistrasiPasien\Models\RegistrasiPasien::find(2007000001) works fine and the data is exist with kelurahan_id = 3
$kelurahan->pasiens the result is null. Shouldn't it show the pasien data that has kelurahan_id = 3?
$kelurahan->pasiens->nama and the result is like this PHP Notice: Trying to get property 'nama' of non-object in D:/PROFESSIONAL/PROJECT/WEB DEVSeval()'d code on line 1 => null
I don't have any idea what's wrong with my codes. Much appreciate for your help guys.
Below are the models that I have made:
DataKelurahan.php
<?php
namespace App\Domain\DataKelurahan\Models;
use Illuminate\Database\Eloquent\Model;
use App\Domain\RegistrasiPasien\Models\RegistrasiPasien;
class DataKelurahan extends Model
{
protected $fillable = ['nama_kelurahan', 'nama_kecamatan','nama_kota'];
public function pasiens(){
return $this->hasMany('RegistrasiPasien');
}
}
RegistrasiPasien.php
<?php
namespace App\Domain\RegistrasiPasien\Models;
use Illuminate\Database\Eloquent\Model;
use App\Domain\DataKelurahan\Models\DataKelurahan;
class RegistrasiPasien extends Model
{
protected $fillable = [
'nama',
'alamat',
'telepon',
'rt',
'rw',
'tgl_lahir',
'jenis_kelamin'
];
public function kelurahan(){
return $this->belongsTo('DataKelurahan');
}
}
And below are my database tables:
data_kelurahans
Schema::create('data_kelurahans', function (Blueprint $table) {
$table->increments('id');
$table->string('nama_kelurahan');
$table->string('nama_kecamatan');
$table->string('nama_kota');
$table->timestamps();
});
registrasi_pasiens
Schema::create('registrasi_pasiens', function (Blueprint $table) {
$table->increments('id');
$table->integer('kelurahan_id')->unsigned();
$table->string('nama');
$table->string('alamat');
$table->char('telepon', 15);
$table->integer('rt');
$table->integer('rw');
$table->date('tgl_lahir');
$table->string('jenis_kelamin');
$table->timestamps();
});
Schema::table('registrasi_pasiens', function (Blueprint $table){
$table->foreign('kelurahan_id')->references('id')->on('data_kelurahans')->onDelete('cascade');
});
From Docs:
Eloquent will automatically determine the proper foreign key column on
the model. By convention, Eloquent will take the "snake case"
name of the owning model and suffix it with _id.
So, Eloquent probably got your foreign key name wrong so you must override the foreign key by passing additional arguments to the hasMany/belongsTo method:
public function pasiens(){
return $this->hasMany('RegistrasiPasien','kelurahan_id');
}
public function kelurahan(){
return $this->belongsTo('DataKelurahan','kelurahan_id');
}

Categories