Laravel 4:使用setTable()的动态表名

时间:2013-08-04 15:35:25

标签: model laravel eloquent

我不确定如何才能使动态表名起作用。

考虑以下模型(表'test'不存在):

<?php

// app/models/Test.php

class Test extends Eloquent {

}

然后如果我这样做('fields'表确实存在):

<?php

// app/routes.php

$test = new \Test;
$test->setTable('fields');
$data = $test->find(1);
dd($data);

我收到错误:

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.tests' doesn't exist (SQL: select * from `tests` where `id` = ? limit 1) (Bindings: array ( 0 => 1, ))"

请注意,从Test模型设置表名称可以正常工作。

L4实际上使用了setTable()方法,非常类似于我想要的方式,在vendor / laravel / framework / src / Illuminate / Database / Eloquent / Relations.Pivot.php构造函数中,尽管我无法得到它按照这个例子来工作。

感谢您的帮助。

3 个答案:

答案 0 :(得分:7)

这可能对您有用:http://laravel.io/forum/08-01-2014-defining-models-in-runtime

更确切地说,从这里开始:http://laravel.io/forum/08-01-2014-defining-models-in-runtime?page=1#reply-11779

class ModelBuilder extends Eloquent {

    protected static $_table;


    public static function fromTable($table, $parms = Array()){
        $ret = null;
        if (class_exists($table)){
            $ret = new $table($parms);
        } else {
            $ret = new static($parms);
            $ret->setTable($table);
        }
        return $ret;
    }

    public function setTable($table)
    {
        static::$_table = $table;
    }

    public function getTable()
    {
        return static::$_table;
    }
}

$user = ModelBuilder::fromTable("users")->find(1);

这不是我的最终实现,因为我的用例,它比那更复杂(更脏)。但我想这个例子可能会引导您达到您的需求。

答案 1 :(得分:0)

您需要覆盖Eloquent Model的静态find方法,因为它用于查找:

public static function find($id, $columns = array('*'))
{
    if (is_array($id) && empty($id)) return new Collection;

    $instance = new static;

    return $instance->newQuery()->find($id, $columns);
}

该方法正在创建模型类的新实例,而不是重用已启用的类。默认情况下,这会忘记&#34;你设定的表格。也许你需要为它传递表名。在我的用例中,我的代码根据id推断出使用过的表,因此我不必传递整个表名。万岁的遗产; - )

其他选择是使用一些额外的工厂类,如 Daniel Cantarin 建议

您可能需要覆盖一些其他静态方法来处理所有用例。例如,我只是注意到使用急切加载会破坏我的表格模式,因此我需要复制with方法的行为,而不会破坏它的调用API,yay -_____-

答案 2 :(得分:0)

Larvael的设计并不完全支持动态模型。虽然有setTable方法,但它的局限性是它的实例方法。此外,在框架内,许多查询都是从通过“new static”创建模型实例开始的,因此您无法在内部查询上设置表。是的,您可以根据自己的查询调用setTable,但是当您使用Laravel的更多功能开发更多应用程序时,例如SoftDeletes forceDelete你会逐渐碰到一堵砖墙。解决方法是使用PHP的eval函数在运行时生成模型类,这样新的静态将按其设计的方式工作。

    // load all the models
    $eval = "namespace App\\Records;";
    foreach($container->tables()->get() as $table){
        $recordType = $table->recordType;
        $recordTable = $table->getRecordTableName();
        $eval .= "class $recordType extends \\App\\Record { protected \$table = '$recordTable'; }";

    }
    eval($eval);

如果我有'Venue'记录类型,使用'场所'recordTable我现在有一个类\ App \ Records \ Venue使用表“场地”,因此我现在可以这样做

$class = "\App\Records\Venue";
$venue = $class::find(1);

现在您可以自由地使用Laravel,而不再使用任何hackery。这是一个非常强大的解决方法,存在安全风险,因此请务必清理eval中使用的任何参数。希望有一天Laravel将实施一种支持动态模型的方法。