6

I'm trying to implement a morphable table for categories, right now I've the following.

// Snippet Table
- id
- title
- body

// Post Table
- id
- title
- body

// Category Table
- id
- name

I want to be able to morph the posts and snippets to have only one category, something like this:

// Categorizable Table
- category_id
- categorizable_id
- categorizable_type

Do I have to have another model for this categorizable table? Or there is a way to set it without another model?

So far I have this

class Snippet extends Model
{
    public function category()
    {
        return $this->morphOne(Category::class, 'categorizable');
    }
}

class Post extends Model
{
    public function category()
    {
        return $this->morphOne(Category::class, 'categorizable');
    }
}

class Category extends Model
{
    public function categorizable()
    {
        return $this->morphTo();
    }
}

And I have 4 tables, snippets, posts, categories, categorizables, the last one the migration looks like this.

Schema::create('categorizables', function (Blueprint $table) {
    $table->increments('id');
    $table->unsignedInteger('category_id');
    $table->morphs('categorizable');
    $table->timestamps();
});

The thing is, what is the correct way to save this relationship, I'm testing it on tinker and bothattach($category_id) and sync($category_id) aren't saving the relationship they return the error BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::categorizable()', What I'm missing?

Big Boss
  • 250
  • 1
  • 3
  • 11
  • Read the docs https://laravel.com/docs/5.4/eloquent-relationships#many-to-many-polymorphic-relations – yazfield May 03 '17 at 23:13
  • @yazfield the documentation shows a morphToMany, and that is not the case, I need a morphOne, in a one-to-one polymorphic relationship. – Big Boss May 03 '17 at 23:30

1 Answers1

14

Sorry I thought you wanted many-to-many relationship. morphOne relationship API is the same as morphMany from the docs

Post extends Model
{
    public function category() {
        return $this->morphOne(Category::class, 'categorizable');
    }
}

Category extends Model
{
    public function categorizable() {
        return $this->morphTo();
    }
}

EDIT When using morphOne you don't need a pivot table categorizables table must be deleted and change your categories table to include the morph fields

// Category Table
- id
- name
- categorizable_id
- categorizable_type
yazfield
  • 1,233
  • 11
  • 18
  • Thanks for the reply, I've updated my question based on your answer, but I think I'm missing something, the category relationship always return null, I've set some itens on the database by hand, and even this way it returns null, the way I can't save the relationship or return it. – Big Boss May 04 '17 at 00:21
  • I got it now, thanks for the help, in the end, I don't think this is what I'll need. =/ – Big Boss May 04 '17 at 04:19
  • I did this but was not working and found out I needed to do one more step. Adding an entry in the Relation::morphMap i.e. `Relation::morphMap([ 'category' => Category::class ]);` Reference: [Laravel docs](https://laravel.com/docs/5.4/eloquent-relationships#many-to-many-polymorphic-relations) – vhen Oct 22 '18 at 02:32
  • It's not only 'morphOne' for which you don't need a pivot table. For 'morphMany' you also don't need it. Except for when its an N-to-N relationship of course. – TheBurgerShot May 24 '19 at 14:21
  • Why is it that the answer and the docs does not state on how to use it – Forbidden Jan 05 '22 at 12:20