Jared Eitnier
Jared Eitnier

Reputation: 7152

Laravel 5 Dynamically create Eloquent Models

Suppose I have an of mysql table names and a row id:

['table_name' => 'things', 'row_id' => 11],
['table_name' => 'stuff', 'row_id' => 5]

Each of these tables has an Eloquent model referencing the table. How can I iterate the list and dynamically use the Model to create a new instance from the table_name key and find the row based on the row_id key?

I can get the data I need through a Builder instance but I really need to construct a Model instance. This is because I am implementing a contract through the Eloquent model and looking for a specific attribute from that contract. I can't get the attribute through the Builder instance.

(The package that I am using: https://github.com/jarektkaczyk/revisionable. I am implementing Revisionable on the models)

To clarify a bit, this works:

dd(\App\Models\Thing::find(11)->latestRevision); // returns Revision model

While this does not:

// foreach($rows as $row)
$model = new Dynamic([])->setTable($row['table_name']);
dd($model->find($row)); // returns model with correct data
dd($model->find($row['row_id'])->latestRevision); // returns null
// endforeach

Please let me know if this is not clear enough.

EDIT:

dd($model->find($row)); // returns model with correct data but shows table as `null` as if it isn't being persisted across the request.

Also, here is the Dynamic model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Sofa\Revisionable\Laravel\RevisionableTrait;
use Sofa\Revisionable\Revisionable;

class Dynamic extends Model implements Revisionable
{
    use RevisionableTrait;

    /**
     * @param $table
     */
    public function __construct($attributes = [])
    {
        parent::__construct($attributes);
    }

    /**
     * Dynamically set a model's table.
     *
     * @param  $table
     * @return void
     */
    public function setTable($table)
    {
        $this->table = $table;

        return $this;
    }
}

Upvotes: 2

Views: 7575

Answers (1)

patricus
patricus

Reputation: 62228

First, latestRevision is a relationship added by the RevisionableTrait, so you need to make sure that your Dynamic class has the use RevisionableTrait; statement.

Next, since the find() method (and any other retrieval methods) return new instances of the models, you will need to reset the table again on every model after you find it. So, your code would look something like:

$model = new Dynamic([]);
$model->setTable($row['table_name']);
$model = $model->find($row['row_id']);
$model->setTable($row['table_name']);
$revision = $model->latestRevision;

Another option, assuming you follow Laravel's naming conventions, is that you could determine the Model name from the table_name, and just use the correct Model from the start, instead of this Dynamic model:

$modelName = Str::studly(Str::singular($row['table_name']));
$model = $modelName::find($row['row_id']);
$revision = $model->latestRevision;

Upvotes: 2

Related Questions