Laravel 4:使用 setTable() 动态表名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18044577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel 4: Dynamic table names using setTable()
提问by T.O.
I'm not sure what do I need to do to get dynamic table names working.
我不确定我需要做什么才能使动态表名正常工作。
Consider following Model (table 'test' does not exist):
考虑以下模型(表“test”不存在):
<?php
// app/models/Test.php
class Test extends Eloquent {
}
and then if I do ('fields' table does exist):
然后如果我这样做(“字段”表确实存在):
<?php
// app/routes.php
$test = new \Test;
$test->setTable('fields');
$data = $test->find(1);
dd($data);
I get an error:
我收到一个错误:
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, ))"
Note that setting the table name from the Test model works just fine.
请注意,从 Test 模型设置表名工作正常。
L4 actually uses setTable() method, very much the way I would want to, in vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations.Pivot.php constructor, though I just couldn't get it to work by following that example.
L4 实际上使用 setTable() 方法,非常像我想要的方式,在 vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations.Pivot.php 构造函数中,尽管我无法让它工作按照那个例子。
Thanks for help.
感谢帮助。
回答by Daniel Cantarin
Perhaps this is useful for you: http://laravel.io/forum/08-01-2014-defining-models-in-runtime
也许这对你有用:http: //laravel.io/forum/08-01-2014-defining-models-in-runtime
More exactly, from here: http://laravel.io/forum/08-01-2014-defining-models-in-runtime?page=1#reply-11779
更准确地说,从这里: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);
That's not my final implementation, which's much more complex (and dirtier) than that because of my use cases. But i guess the example may lead you to what you need.
这不是我的最终实现,由于我的用例,它比我的实现要复杂得多(也更脏)。但我想这个例子可能会引导你找到你需要的东西。
回答by trm42
You need to override Eloquent Model's static find
method as it's used for find:
您需要覆盖 Eloquent 模型的静态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);
}
That method is creating new instance of your model class instead of reusing the instiated class. By default this "forgets" the table you've set. And probably you need to pass the table name for it. In my use case my code infers the used table based on the id
so I don't have to pass the whole table name. Hooray for legacy ;-)
该方法正在创建模型类的新实例,而不是重用已启动的类。默认情况下,这会“忘记”您设置的表格。并且您可能需要为它传递表名。在我的用例中,我的代码基于 推断使用过的表,id
因此我不必传递整个表名。万岁的遗产;-)
Other option is to use some additional factory class like Daniel Cantarinsuggested
其他选择是使用一些额外的工厂类,如Daniel Cantarin建议的
You may need to override some additional static methods to handle all use cases. For example I just noticed that using eager loading breaks my table mods, so I need to copy with
method's behaviour without breaking it's calling API, yay -_____-
您可能需要覆盖一些额外的静态方法来处理所有用例。例如,我刚刚注意到使用预先加载会破坏我的 table mods,所以我需要复制with
方法的行为而不破坏它的调用 API,是的 -_____-
回答by malhal
Larvael's design doesn't fully support dynamic models. Although there is the setTable method its limitation is its an instance method. Furthermore within the framework a lot of queries begin with creating a model instance via "new static", thus there is no way for you to set the table on the internal queries. Yes you can call setTable on your own queries but as you develop more of your application using more of Laravel's features, e.g. SoftDeletes forceDelete you will gradually come up against a brick wall. A work around is to use PHP's eval function to generate model classes at runtime, that way new static will work the way it was designed.
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);
In the case of when I have a 'Venue' recordType that uses the 'venue' recordTable I now have a class \App\Records\Venue that uses the table "venue", thus I can now do this
如果我有一个使用“场地”记录表的“场地”记录类型,我现在有一个使用表“场地”的类 \App\Records\Venue,因此我现在可以执行此操作
$class = "\App\Records\Venue";
$venue = $class::find(1);
Now you are free to use Laravel as designed without any more hackery. This is a very powerful workaround that comes with a security risk, so be sure to sanitise any parameters used in eval. Hopefully someday Laravel will implement a way to support dynamic models.
现在,您可以按照设计自由使用 Laravel,而无需再进行任何黑客攻击。这是一个非常强大的变通方法,伴随着安全风险,所以一定要清理 eval 中使用的任何参数。希望有一天 Laravel 能够实现一种支持动态模型的方法。