2

我不确定我需要做什么才能使动态表名正常工作。

考虑以下模型(表“测试”不存在):

<?php

// app/models/Test.php

class Test extends Eloquent {

}

然后如果我这样做(“字段”表确实存在):

<?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 构造函数中,尽管我无法让它工作按照那个例子。

感谢帮助。

4

3 回答 3

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);

这不是我的最终实现,由于我的用例,它比这更复杂(也更脏)。但我想这个例子可能会引导你找到你需要的东西。

于 2014-08-03T04:40:11.603 回答
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);
}

该方法正在创建模型类的新实例,而不是重用已启动的类。默认情况下,这会“忘记”您设置的表格。并且可能您需要为其传递表名。在我的用例中,我的代码根据 推断使用的表,id因此我不必传递整个表名。万岁遗产 ;-)

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

您可能需要重写一些额外的静态方法来处理所有用例。例如,我刚刚注意到使用急切加载会破坏我的表模块,所以我需要复制with方法的行为而不破坏它正在调用 API,是的 -_____-

于 2015-02-02T14:33:01.187 回答
0

Larvael 的设计并不完全支持动态模型。虽然有 setTable 方法,但它的限制是它的实例方法。此外,在框架内,许多查询都是从通过“新静态”创建模型实例开始的,因此您无法在内部查询上设置表。是的,您可以在自己的查询中调用 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);

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

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

现在你可以自由地使用 Laravel 的设计,而无需任何黑客攻击。这是一个非常强大的解决方法,但会带来安全风险,因此请务必清理 eval 中使用的任何参数。希望有一天 Laravel 将实现一种支持动态模型的方法。

于 2015-07-10T13:19:18.513 回答