Switch88
Switch88

Reputation: 130

Laravel 7 - belongsTo relation - Trying to get property of non-object

Before I start: I already read the "Similar questions" suggestions, and although there are indeed many similar questions with problem like mine, I haven't find the solutions yet. I also only started to learn Laravel for a few days, so please bear with me.

I'm using the latest Laravel framework (7.18.0). I have three tables:

pirates
----------
pirate_id serial NOT NULL, -- PK
pirate_name character varying(200) NOT NULL,
beard_size integer NOT NULL,
beard_color integer NOT NULL,

beard_sizes
----------
beard_size_id serial NOT NULL, -- PK
beard_size character varying(100) NOT NULL

beard_colors
----------
beard_color_id serial NOT NULL, -- PK
beard_color character varying(100) NOT NULL

I generated the model with php artisan command and tried to define the models:

Pirate.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Pirate extends Model
{
    public $timestamps = false;
    
    protected $primaryKey = 'pirate_id';
    
    protected $fillable = ['pirate_name', 'beard_size', 'beard_color'];
    
    public function beardSize()
    {
        return $this->belongsTo('App\BeardSize', 'beard_size_id');
    }
    
    public function beardColor()
    {
        return $this->belongsTo('App\BeardColor', 'beard_color_id');
    }
}

BeardSize.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class BeardSize extends Model
{
    public $timestamps = false;
    
    protected $primaryKey = 'beard_size_id';
    
    protected $fillable = ['beard_size'];
    
    public function pirates()
    {
        return $this->hasMany('App\Pirate', 'pirate_id');
    }
}

BeardColor.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class BeardColor extends Model
{
    public $timestamps = false;
    
    protected $primaryKey = 'beard_color_id';
    
    protected $fillable = ['beard_color'];
    
    public function pirates()
    {
        return $this->hasMany('App\Pirate', 'pirate_id');
    }
}

Tried to display my "pirates" table's data, this is my controller:

PirateController.php

<?php

namespace App\Http\Controllers;

use App\Pirate;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class PirateController extends Controller
{
    public function main()
    {
        $pirates = Pirate::paginate(4);
        
        return view('main', ['pirates' => $pirates]);
    }
}

and here is my view:

main.blade.php

@extends('pirate')

@section('main_nav', 'This is our ship')

@section('main_content')

<p>List of our crew:</p>

<table class="table-view">
    <thead>
        <tr>
            <th style="width: 60px;">No.</th>
            <th>Name</th>
            <th style="width: 160px;">Beard size</th>
            <th style="width: 160px;">Beard color</th>
            <th>&nbsp;</th>
            <th>&nbsp;</th>
        </tr>
    </thead>
    <tbody>
        @foreach($pirates as $ind => $pirate)
        <tr>
            <td>{{ ($ind + 1) . '.' }}</td>
            <td>{{ $pirate->pirate_name }}</td>
            <td>{{ $pirate->beardSize->beard_size }}</td>
            <td>{{ $pirate->beardColor->beard_color }}</td>
            <td class="table-nav"><a href="update/{{$pirate->pirate_id}}">edit</a></td>
            <td class="table-nav"><a href="delete/{{$pirate->pirate_id}}">delete</a></td>
        </tr>
        @endforeach
    </tbody>
</table>

{{ $pirates->links() }}

@endsection

Every time I tried to get the relation table's data (beard_sizes and beard_colors), I got errors either: Trying to get property 'beard_size' of non-object or Trying to get property 'beard_color' of non-object. For the record, the beard_size and beard_color column in pirates table are not null.

Regarding the field names in the database tables, the documentation mentioned how primary key should be written with id, etc., however in my next project, I'm using an already existing database with 100+ tables, so changing the name of the columns is impossible.

Upvotes: 1

Views: 1568

Answers (2)

Martin Zeitler
Martin Zeitler

Reputation: 76699

NOT NULL probably does not suffice for a primary key; set it to UNSIGNED, BIGINT and enable AUTOINCREMENT. The name of the column does not really matter. I mean, usually one can simply define it's name: protected $primaryKey = 'pirate_id'; ...as you already have it.

And the one-to-many relationship of App\Pirate should be represented as:

Well, actually it's one-to-one ...as 1 pirate only has 1 beard.

public function beardSize()
{
    return $this->hasOne('App\BeardSize', 'beard_size_id');
}

public function beardColor()
{
    return $this->hasOne('App\BeardColor', 'beard_color_id');
}

Upvotes: 1

Kurt Friars
Kurt Friars

Reputation: 3764

With your schema you have provided you need to have the following relationships:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Pirate extends Model
{
    public $timestamps = false;
    
    protected $primaryKey = 'pirate_id';
    
    protected $fillable = ['pirate_name', 'beard_size', 'beard_color'];
    
    public function beardSize()
    {
        return $this->belongsTo('App\BeardSize', 'beard_size', 'beard_size_id');
    }
    
    public function beardColor()
    {
        return $this->belongsTo('App\BeardColor', 'beard_color', 'beard_color_id');
    }
}

A belongsTo relationship has the following structure:

     return $this->belongsTo(Related::class, 'key_on_own_table', 'key_on_related_table');

Upvotes: 2

Related Questions