Have you ever found yourself trying to manage multiple relationships between different models in your Laravel application? If so, you're in for a treat! Today we'll explore the concept of morph relationships in Laravel–a neat feature that introduces polymorphism to your database design, making your application more robust and elegant.
What Are Morph Relationships?
Morph relationships (or polymorphic relationships) allow one model to be associated with multiple other models using a single, unified relationship. Imagine having a single database table that can dynamically reference multiple types of parent models. That's exactly what it does in simple terms!
Instead of having to create several pivot tables for each relationship or foreign keys, morph relationships let you streamline your database schema.
There are a total of 3 types of polymorphic relationships:
- One-to-One
- One-to-Many
- Many-to-Many
We'll go over each one in detail, how to create them and how to use them in practice.
One-to-One Polymorphic Relationships: A Picture-Perfect Example
Let's start off with a simple and, most likely, a scenario you've already encountered. Suppose both Users and Businesses need to have an address. Instead of creating separate tables for each, you can create one versatile addresses table that caters to both.
The Setup
Imagine an addressables table structured like this:
- id: The unique identifier of the address.
- addressable_id: The foreign key of the model that the address belongs to.
- addressable_type: The class name of the owning model (in our case, either User or Business).
Here's what the migration for this table might look like:
You can add more tables to this migration if you'd like, these will act just like pivot columns.
In Your Models
Next, you define the relationships in your models. In the Address model, you'll add the following:
And in your User and Business models, you'll use the morphOne method:
How It Works in Practice
Let's attach an address to a user:
Or to a business:
In both cases Laravel handles the magic by storing the correct addressable_id and addressable_type values.
One-to-Many Polymorphic Relationships
Or wait. What if you wanted that both Videos and Posts have multiple Comments? Instead of creating a pivot table for the both, you can use a one-to-many polymorphic relationship.
The Database Design
Your comments table would include something like the following:
- id: The unique identifier.
- content: The content of the comment in text format.
- commentable_id: The ID of the parent model.
- commentable_type: the class name of the parent model (in this case, Video or Post).
Your migration should then look something like this:
In Your Models
First define the relationship in the Comment model:
And let's not forgot your Video and Post models:
Using It
Adding a comment is again, pretty easy:
And for a post:
Many-to-Many Polymorphic Relationships
Let's consider a scenario where you have Children that can be attached to both Guardians and Schools. Instead of multiple pivot tables, you can have a single, unified pivot table.
The Schema
You'd have a children table for, well, storing the children and a pivot table called childables with the following columns:
- child_id: The ID of the child.
- childable_id: The ID of the parent model.
- childable_type: The class name of the parent model.
A look at what the migration might include:
In Your Models
In your Child model, define the relationships to your School and Guardian models:
And of course, do the same for your Guardian and School models:
Making It Work
Attaching a child should look like this:
And it works the exact same for guardians:
This makes it extremely ease to extend this by, for example, adding another model that can "own" children.
Wrapping Up
Laravel's morph relationships make the developer experience much better and smoother, and makes your application more robust and maintainable. By using this you avoid unnecessary repetition in your database schema's and simplify your codebase. It can take a while to understand what exactly this does or what effect it has, but it is a must in any Laravel project. Unless you like writing boilerplate, then keep doing what you're doing, I guess.
So the next time you're faced with any model relationships, make sure to make use of this Laravel feature. You'll thank yourself for doing so!
Happy coding!