Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Polymorphic Eloquent relationships with namespaces

I've tried to implement polymorphic relationships. They work perfectly... However, I'm trying to reduce my database size as much as possible so... I've this

Table action
|  id  |  realatable_type  |  relatable_id
|  1   |  Lion\People      |  65
|  2   |  Lion\Company     |  13

Obviously I've this

<?php namespace Lion;

class Company extends \Eloquent { ... }
class People extends \Eloquent { ... }

Is there any way to store only "People" or "Company" assuming that the namespace is always going to be "Lion"?

like image 247
Israel Ortuño Avatar asked Nov 09 '13 19:11

Israel Ortuño


2 Answers

Since Laravel 4.1, inside your model (in this case Company and People) you can set the protected property $morphClass to whatever you want.

<?php namespace Lion;

class Company extends \Eloquent { 

    protected $morphClass = 'Company';
}

Now in your table you can store the type without the namespace:

 |  id  |  realatable_type  |  relatable_id
 |  2   |  Company          |  13
like image 166
Rodri_gore Avatar answered Sep 30 '22 21:09

Rodri_gore


I believe the best solution here (for database size at least) would be to simply change readable_type to ENUM('Lion\Company', 'Lion\People').


That being said, if you really want to handle this on Laravel side, you'll have to create new classes extending from Illuminate\Database\Eloquent\Relations\Morph* ¹ and overwrite their constructors ² as to get only the last value after a dash, on $morphClass. Something like this:

<?php

use \Illuminate\Database\Eloquent\Model;
use \Illuminate\Database\Eloquent\Builder;

class MyMorphOne extends \Illuminate\Database\Eloquent\Relations\MorphOne {
    public function __construct(Builder $query, Model $parent, $type, $id) {
        parent::__construct($query, $parent, $type, $id);

        $this->morphClass = substr($this->morphClass, strrpos($this->morphClass, '\\') + 1);
    }
}

Then, extend your own model or base model, to overwrite morphOne, morphMany and morphToMany methods as to make use of your new extended classes. Something like this:

<?php

class People extends Eloquent {

    // ...

    public function morphOne($related, $name, $type = null, $id = null) {
        $instance = new $related;

        list($type, $id) = $this->getMorphs($name, $type, $id);

        $table = $instance->getTable();

        return new MyMorphOne($instance->newQuery(), $this, $table.'.'.$type, $table.'.'.$id);
    }

}
  1. * = One, Many and ToMany
  2. Which are actually inherited from MorphOneOrMany on MorphOne and MorphMany.
like image 34
rmobis Avatar answered Sep 30 '22 22:09

rmobis