Update the table name at runtime not working - laravel Eloquent ORM

The problem with the accepted answer is, that modifying the retrieved model instance and later on saving it won't work. See my comment above.

The following trait allows for passing on the table name during hydration.

trait BindsDynamically
{
    protected $connection = null;
    protected $table = null;

    public function bind(string $connection, string $table)
    {
        $this->setConnection($connection);
        $this->setTable($table);
    }

    public function newInstance($attributes = [], $exists = false)
    {
        // Overridden in order to allow for late table binding.

        $model = parent::newInstance($attributes, $exists);
        $model->setTable($this->table);

        return $model;
    }

}

Here is how to use it:

class Product extends Model
{
    use BindsDynamically;
}

Applied to the accepted answer:

$product = new Product;
$product->getTable(); // products
$product->bind('connection', 'oooops');
$product->get(); // select * from oooops
$product->first(); // select * from oooops limit 1
etc...
$product->myTestProp = 'test;
$product->save(); // now saves into oooops

this should work with static methods also (only tested on 5.7)

use Illuminate\Database\Eloquent\Model;

function makeModel($table)
{
    $model = new class extends Model
    {
        public static $entryTable;

        public function setTable($table)
        {
            $this->table = static::$entryTable = $table;
        }

        public static function __callStatic($method, $parameters)
        {
            $static = (new static);
            $static->setTable($static::$entryTable);

            return $static->$method(...$parameters);
        }
    };
    $model->setTable($table);

    return $model;
}

I needed to change the table name based on my request (my tables would have a prefix based on my request). what I did was that I extended the Model class as MyModel, then I overrode the construct method, combining a table name based on my request and the default table name I provided my models.

class MyModel extends Model
{

  public function __construct(array $attributes = [])
  {
      parent::__construct($attributes);
      $this->setTable(Config::get('tablePrefix').$this->getTable());
  }
}

which you should replace the Config table prefix towards your approach.

and then in my models I just extended MyModel and all was fine including static calls as I tested.

class Category extends MyModel
{

  protected $table = "categories";
}

So as my request changed I changed the Config I had provided and could get different table names such as a__categories, b__categories and all was fine including static calls, relations and saving to database.


all() is a static method that uses brand new instance and calls get() on it.

So all you need is using proper method:

$product = new Product;
$product->getTable(); // products
$product->setTable('oooops');
$product->get(); // select * from oooops
$product->first(); // select * from oooops limit 1
etc...

Just avoid using static Eloquent methods, since they obviously create new instance, that will have default table property.