Working with Polymorphic Relations in Laravel 5 - Create,Save,Update,Delete, and Filter Actions


Laravel 5 Polymorphic relationship explained in detail


When considering an interface for document management on different types of entities (Employees, Customers, Companies and departments, for example) on an enterprise system, one might presume it is necessary to manage each type of document separately. This approach would however be repetitive because each document model would presumably consist of the same data structure. You can eliminate this repetition using a Laravel polymorphic relation, resulting in all documents being managed via a single Document model.

Incidentally, although the models found in this post using Laravel 5-specific syntax, it may be compatible with Laravel 4 since it supports polymorphic relations.

Let's work through an example that would use polymorphic relations to add document capabilities to the Employee and Customer models. Begin by creating a new model named Document, by creating a file named Document.php and placing it in the project's app directory:

<?php namespace App;
use Illuminate\Database\Eloquent\Model;

class Document extends Model {
  protected $fillable = [];
}

Next, generate the associated database table that will store document data:

$ php artisan make:migration create_documents_table --create=documents 
Created Migration: 2018_04_11_205601_create_documents_table

Next, open up the newly generated migration file and modify the up() method to look like this:

Schema::create('documents', function(Blueprint $table)
{
  $table->increments('id');
  $table->string('file_name');
  $table->string('file_path');
  $table->string('description');
  $table->integer('documentable_id');
  $table->string('documentable_type');
  $table->timestamps();
});

Finally, save the changes and run the migration:

$ php artisan migrate
Migrated: 2018_04_11_205601_create_documents_table

Because the Document model serves as a central repository for documents associated with multiple different entities, we require a means for knowing both which model and which record ID is associated with a particular document. The documentable_type and documentable_id fields serve this purpose. For instance, if a document is associated with an employee, and the employee record associated with the document has a primary key of 22, then the document's documentable_type field will be set to App\Employee and the documentable_id to 22.

Logically you'll want to attach other fields to the documents table if you plan on for instance assigning ownership to documents via the Employee model, or would like to include a name for each document.

Next, open the Document model and add the following method:

class Document extends Model {

    public function documentable()
    {
      return $this->morphTo();
    }
}

The morphTo method defines a polymorphic relationship. Personally I find the name to be a poor choice; when you read it just think "belongs To" but for polymorphic relationships, since the record will belong to whatever model is defined in the documentable_type field. This defines just one side of the relationship; you'll also want to define the inverse relation within any model that will be documentable, creating a method that determines which model is used to maintain the documents, and referencing the name of the method used in the polymorphic model:

class Employee extends Model {

  public function documents()
  {
    return $this->morphMany('App\Document', 'documentable');
  }

}

class Customer extends Model {

  public function documents()
  {
    return $this->morphMany('App\Document', 'documentable');
  }

}

With these two methods in place, it's time to begin using the polymorphic relation! The syntax for adding, removing and retrieving documents is straightforward; in the following example we'll attach a new document to an employee and customer:

$employee = Employee::find(22);

$document = new Document();
$document->file_name = 'passport-front.png';
$document->description = 'Passport Front Page';

$employee->documents()->save($document);

and attach a document to customer model:

$customer = Customer::find(39);

$document = new Document();
$document->file_name = 'invoice-may-2018.pdf';
$document->description = 'Invoice for May 2018';

$customer->documents()->save($document);

After saving the document, review the database and you'll see a record that looks like the following:

mysql> select * from documents;
+----+--------------------+----------------+---------------------+------------+------------+
| id |      file_name     | documentable_id| documentable_type   | created_at | updated_at |
+----+--------------------+----------------+---------------------+------------+------------+
|  1 | passport-front.png |      22        |     App\Employee    | 2018-...   | 2018-...   |
+----+--------------------+----------------+---------------------+------------+------------+
+----+--------------------+----------------+---------------------+------------+------------+
|  2 | ..ice-may-2018.pdf |      39        |     App\Customer    | 2018-...   | 2018-...   |
+----+--------------------+----------------+---------------------+------------+------------+

The employee's documents are just a collection, so you can easily iterate over it. You'll retrieve the employee within the controller per usual:

public function index()      
{
  $employee = Employee::find(1);
  return view('employee.show')->with('employee', $employee);
}

In the corresponding view you'll iterate over the documents collection:

@foreach ($employee->documents as $document)
    <p>
      {{ $document->file_name }}
    </p>
    <p>
      {{ $document->file_path }}
    </p>
    <p>
      {{ $document->description }}
    </p>
  @endforeach

Polymorphic relations can no doubt save a great deal of time and effort when you'd like models to share a particular feature such as documents, notes or contacts on an enterprise system.

If you have any other questions, experience or insights on "Creating , Using Laravel polymorphic relations" please feel free to leave your thoughts in the comments bellow which might be helpful to someone some day!

Written by Akram Wahid 4 years ago

are you looking for a chief cook who can well craft laravel and vuejs, to make some awsome butterscotch,
yes then it is right time for you to look at my profile.

Do you want to write Response or Comment?

You must be a member of techalyst to proceed!

Continue with your Email ? Sign up / log in

Responses

Be the first one to write a response :(

{{ item.member.name }} - {{ item.created_at_human_readable }}

{{ reply.member.name }} - {{ reply.created_at_human_readable }}