Michael

Polymorphic relations with Eloquent and Laravel 5

When you're developing a system that is supposed to work with multiple content types (or any other data structures), polymorphism can be quite helpful. Today we'll talk about how to organise your database schema and use Eloquent to implement polymorphic relations between your models.

Short intro

You know, sometimes when you're reading through a tutorial, it's not always clear from the snippets how to actually use them and you want more detail. It can be very frustrating and I'm sure that many of you have been in that situation, especially when you were trying to learn some completely new stuff. So we decided to go further than just providing you with snippets. We'll provide you with a fully functional Laravel application with migrations, models and unit tests.

Grab this repo here for examples used in this post:

https://github.com/Webscope/laravel-eloquent-polymorphic

It's based on our Laravel base setup which you are more than welcome to use as a base for your own projects:

https://github.com/Webscope/laravel-base

Let's get some work done

Imagine that your website needs to work with 2 types of content: articles and events. They both have a title. Articles have a body and Events have a date. We don't want to have a single table that will be used for both models. Instead we want to separate the content into 3 tables – one for generic data, one for event-specific data, and one for article-specific data.

Eloquent makes it really easy to setup and use.

Let's create our models first. They are already created in the repo, by the way.

php artisan make:model Models/Content
php artisan make:model Models/Article
php artisan make:model Models/Event

Content will be a parent table containing the generic properties for articles and events.

Database migrations

Please go to the database/migrations folder.

The Content table will have 2 extra columns for referencing Articles and Events. content_data_id will be used for storing the Article/Event ids and content_data_type will store the class name of the Article/Event model. The easiest way to set those up is to use the morphs() method. It will create the required columns for you. You just need to provide the relationship key to that method, which in this case is content_data. That key is like a machine name for that relationship and it can have any name that suits your needs. You can also setup the columns manually.

Articles and Events migrations are very straightforward and don't require any extra setup.

Models

Please go to app/Models and check out all the models.

We'll need to setup a few methods on our models to enable the relationship between them. Please note that we're providing the relationship key as one of the arguments. Content model is using the morphTo() method, and Article and Event models use the morphOne() method, because it's a one-to-one relationship.

Tests

Please refer to tests/unit/Models

It's very easy to unit test Eloquent relations with Mockery. We just need to make sure that the morphTo() and morphOne() methods are actually being called and that they are called with correct arguments. We don't really need to test further than that.

Using polymorphic relations

ContentTest.php contains an integration test which shows how to actually use the polymorphic relation. The main idea is that you create a child model first (an Article), then you attach it to the parent (Content model) and you save the parent. If you'll try to create and save the parent first, Eloquent will give an error, because the content_data_id and content_data_type cannot have null values.

More blog posts by Michael Kudenko

Ansible is a great tool for automating tasks executed either locally or remotely. Today we will talk about using Ansible in conjunction with Vagrant for setting up a local development environment.
Previously we have talked about the benefits of using virtual machines for local development and how Vagrant and Ansible help you manage your VMs. In this post we will talk about the Vagrant part of our setup.
Here at Webscope we pay a great deal of attention to our development process. We are working hard to make it as smooth and efficient as possible. We find that developing locally, as opposed to remotely, provides greater benefits. In this post we'll talk about streamlining our local development with Vagrant and Ansible.