Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

nerdroid's avatar

Best way to set up relationships

So i have 4 models: Category.php, Monograph.php, FlashCard.php and QuestionPool.php. When a category is created, it is assigned a subject_type, and the subject_type defines which models (Monograph.php, FlashCard.php or QuestionPool.php) can be attached to the category.

// Category.php
class Category extends Model
{
    protected $fillable = [
		// ... other properties
        'subject_type',
    ];
}

// Monograph.php
class Monograph extends Model
{
    protected $fillable = [
		// ... other properties
        'category_id',
    ];

    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class);
    }
}

// FlashCard.php
class FlashCard extends Model
{
    protected $fillable = [
		// ... other properties
        'category_id',
    ];

    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class);
    }
}

// QuestionPool.php
class QuestionPool extends Model
{
    protected $fillable = [
		// ... other properties
        'category_id',
    ];

    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class);
    }
}

Ideally, I want to have a method on the Category.php model that returns either the Monograph.php, FlashCard.php or QuestionPool.php that are attached to the Category.php based on the subject_type. Something like this:

// Category.php
class Category extends Model
{
	// ... other methods & properties

    public function subjects(): HasMany
    {
        return match ($this->evaluation_type) {
            EvaluationType::Monograph() => $this->hasMany(Monograph::class, 'category_id'),
            default => throw new \Exception('Invalid subject type.'),
        };
    }
}

The issue with this is that $this inside the method refers to a skeleton of the model, there are no properties set on the model because the query has yet to be executed. I am wondering if a polymorphic relationship would be better suited for this however I haven't been able to wrap my head around how it would need to be structured. Any tip would be greatly appreciated!

0 likes
1 reply
SilenceBringer's avatar

@nerdroid you can't define dinamic relationship if you want to grab multiple categories at once

Instead you can define 3 relationships in category: monographs, flashCards and questionPools, each one is hasMany, have a method on Category like

    public function subjects(): HasMany
    {
        return match ($this->evaluation_type) {
            EvaluationType::Monograph() => $this->monographs,
            EvaluationType::FlashCard() => $this->flashCards,
            EvaluationType::QuestionPool() => $this->questionPools,
            default => throw new \Exception('Invalid subject type.'),
        };
    }

then load it as

Category::with('monographs', 'flashCards', 'questionPools')->get()

in total - 4 db queries

for single model you can use it without eager loading - appropriate relationship will be loaded automatically according to evaluation_type

Category::first()->subjects()
1 like

Please or to participate in this conversation.