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

jst's avatar
Level 2

Polymorphic or not?

Hello,

I am just designing my data model and came upon a special case, where I'm not sure which kind of relationship is the best choice.

We have a model Installation which has an unique id and a type (one of 6 possible types), and which is the basis for our billing system. Each Installation then has to have some details which depend on the type, i.e Heat, Power, Water,... , which include some specialized technical, organisational, and even billing informaton.

When the Installation is of type Heat then the details can be found in the table install_heat; when it is Power in install_power, when it is Water in install_water.

So the schema looks something like this:

installations
    id - unique integer, primary key
    type - integer (1 for Heat, 2 for Power, 3 for Water, ...)
    ... other stuff

install_heat
    id - primary key
    installation_id - foreign key to installations table
    ... other stuff specific to Heat installations

install_power
    id - primary key
    installation_id - foreign key to installations table
    ... other stuff specific to Power installations

install_water
    id - primary key
    installation_id - foreign key to installations table
    ... other stuff specific to Water installations

As you can see, the install_* tables just provide some specialized details for an Installation. So it basically is a One-to-One, but where the second side can reside in any of the install_* tables. That's why I was thinking of this being polymorphic.

I currently plan to to it this way:

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

and for the installation types:

class InstallType1 extends Model
{
    public function main()
    {
       return $this->morphOne(Installation::class, 'details');
    }
}

What do you think, is this a good way to go? Or am I missing something crucial?

Thanks in advance for any comments!

Edit: clarified the setup.

0 likes
17 replies
mstnorris's avatar

Can the Type belong to any other model? If not, then it isn't Polymorphic, just a standard One to Many.

Can you show us your schema design and give any more information so we can better inform you.

jst's avatar
Level 2

No each Installation has exactly one type, i.e. the details are in exactly one install_type# table. I would like to access these details then via $install->details for any of the installation types.

Edit: Updated the first post with some schema info.

mstnorris's avatar

Then it is a One to Many relationship.

Installation Model

// you could rename this to details; if you do then you will have to add the relevant arguments to the method below. See http://laravel.com/docs/5.1/eloquent-relationships#one-to-many
public function type() {
    return $this->belongsTo(Type::class);
}

Type Model

public function installations() {
    return $this->hasMany(Installation::class);
}
jst's avatar
Level 2

I don't think that Many-to-Many or One-to-Many matches this, since the installation does only ever refer to one other detail table; and the detail table only ever references one installation. The Type is not really a graspable model.

Basically there is some additional information for each Installation, which depending on the type is stored in different tables/models.

jst's avatar
Level 2

You are right, I can do it this way, but then I have to have multiple functions like this:

public function type1() {
    return $this->belongsTo(Type1::class);
}
public function type2() {
    return $this->belongsTo(Type2::class);
}
public function type3() {
    return $this->belongsTo(Type3::class);
}
...

and I then cannot refer to the details like

Installations::find(1)->details

which should return the appropriate details from the connected type table.

In a way, I think that this is polymorphic on the Installation side.

mstnorris's avatar

@jst you wouldn't have to do that at all.

You store the type_id on the installations table and that is what Eloquent gives you.

Check out this lesson on Eloquent Relationships. By the looks of things you're overcomplicating it where in actual fact this is very easy and pretty common. The example in the video refers to Users and Articles where a User belongsToMany Article and an Article hasOne User which is the same relationship you're describing.

jst's avatar
Level 2

But the difference is that - to use your analogy - in my case the User wouldn't have many Articles, but either exactly one Article, OR exactly one Photo, OR exactly one Link,... there would never be any mix of these. Basically it would be a user that either wrote exactly one article, or would have shot one photo, or provided one link, but never have more than one contribution.

PS: How can I make these bold class formatting here in the forums?

mstnorris's avatar

Use two asterisks for bold **this is bold**

Can the install type can be used by many installations? Or are the Install Type configurations unique?

If not, then it is even simpler, it is a One to One relationship where it is more like a User and their Profile where a User hasOne Profile and the Profile belongsTo a User.

jst's avatar
Level 2

Ah, thanks!

There is a misunderstanding, probably caused by my use of the word "type". I didn't explain this thoroughly enough.

The Installation doesn't refer to a Type, but it does have a certain type, lets call them Heat, Power, Water to be more specific. When the Installation is of type Heat then the details can be found in the table install_heat; when it is Power in install_power, when it is Water in install_water. So the schema looks like this:

installations
    id - unique integer, primary key
    type - integer (1 for heat, 2 for power, 3 for water, ...)
    ... other stuff

install_heat
    id - primary key
    installation_id - foreign key to installations table
    ... other stuff specific to heat installations

install_water
    id - primary key
    installation_id - foreign key to installations table
    ... other stuff specific to water installations

install_power
    id - primary key
    installation_id - foreign key to installations table
    ... other stuff specific to power installations

As you can see, the *install_#### tables just provide some specialized details for an Installation. So it basically is a One-to-One, but where the second side can reside in any of the *install_#### tables. That's why I was thinking of this being polymorphic.

mstnorris's avatar

It looks to me as though you're repeating a lot of data/work.

I would go with a general Many to Many relationship in this case between Installation and Type and then a One to One relationship between Type and TypeDetail so you have access to the specifics.

PLB-RR's avatar

The detail of the types, are those used for anything or is it just to show extended information to the user/admin?

jst's avatar
Level 2

Actually, I'm not repeating any data. The TypeDetail you are referring to looks completely different for each type of installation. I need to have one table for each type to hold the specialized information. For example every Power installation has a max current, every Water installation has a pressure, every Heat installation has a target_temperature,... So I have this information in the various install_* tables, which then refer to the Installation with an installation_id. The Type itself doesn't hold any information, so it can just be seen as an integer.

jst's avatar
Level 2

@PLB-RR Yes, the details of the Installation are used to hold technical information, organisational information and even billing information for each Installation, always according to the type of the Installation.

As explained in the post just above, the Type itself doesn't hold any information at all. The install_* are basically just specialized details tables for the Installations in the installations table. If I wanted to, I could just add all the fields from the install_* tables to the main installation table and leave the unused ones empty, but that would be a mess and IMO really bad design.

PLB-RR's avatar
PLB-RR
Best Answer
Level 3

@jst I think I would go for a morph relation. I believe it is the cleanest solution for this.

PLB-RR's avatar

@jst Your welcome, did you solved it with morphing the install types?

Please or to participate in this conversation.