Search code examples
phplaraveleloquentmodels

Accessing Eloquent relationship attributes


I have three models all related by one-to-many. Category, Subcategory and Style. I have relationships working both ways - though I seem to have a problem accessing related attributes.

After my queries have ran, I'm left with this an instance of Style where 'relations' is an instance of Subcategory, and 'relations' in Subcategory is an instance of Category. Which is all correct.

The problem is that I now seem to not be able to access the related model instances. For example, if I call:

$style->subcategory->name;

I get 'Trying to get property of non-object'. So I tried calling just $style->subcategory and the result is '1'.

Why doesn't $style->subcategory return the instance of the subcategory model? Am I missing something or is my understanding incorrect?

--EDIT--

Models

Category

<?php

namespace Paragon\Products;

use Illuminate\Database\Eloquent\Model as Eloquent;

class Category extends Eloquent {

    protected $table = 'product_categories';

    protected $fillable = [
            'name',
            'slug',
            'image'
    ];

    public function subcategories() {
            return $this->hasMany('Paragon\Products\Subcategory', 'category');
    }

}

Subcategory

<?php

namespace Paragon\Products;

use Illuminate\Database\Eloquent\Model as Eloquent;

class Subcategory extends Eloquent {

    protected $table = 'product_subcategories';

    protected $fillable = [
            'category',
            'name',
            'slug',
            'image'
    ];

    public function styles() {
            return $this->hasMany('Paragon\Products\Style', 'subcategory');
    }

    public function category() {
            return $this->belongsTo('Paragon\Products\Category', 'category');
    }

}

Style

<?php

namespace Paragon\Products;

use Illuminate\Database\Eloquent\Model as Eloquent;

class Style extends Eloquent {

    protected $table = 'product_styles';

    protected $fillable = [
            'subcategory',
            'name',
            'slug',
            'image'
    ];

    public function subcategory() {
            return $this->belongsTo('Paragon\Products\Subcategory', 'subcategory');
    }

}

Query

$style->where($id, $item)->with('subcategory.category')->first();

Tables

Paragon\Products\Category

ID    ...
1
2

Paragon\Products\Subcategory

ID   Category    ...
1    2
2    2

Paragon\Products\Style

ID   Subcategory    ...
1    1
2    1

Since the subcategory method in the Style model should refer to a single instance of Subcategory and not a Collection of them, shouldn't I be able to just call attributes the way I am (or am trying to)?


Solution

  • Ok I think I see now what is going on. Your Eloquent model is called subcategory, but so is the foreign key. So when you call

    $style->subcategory
    

    That is returning the foreign key instead of the model. To fix this, I'd recommend changing the name of the foreign key id to subcategory_id. If you can't change the database, you could force it to use the model by chaining the method with something like this

    $style->subcategory()->first()->name
    

    Edit: Another idea, you could change the name of the relationship to something like

    public function subcategory_item()
    {
      return $this->belongsTo('Paragon\Products\Subcategory', 'subcategory');
    }
    

    Then you ought to be able to properly reference it with

    $style->subcategory_item->name