按 Table 名称查找 Eloquent Class
Find Eloquent Class by Table Name
我目前正在围绕遗留数据库 Laravel/Eloquent 包装并建立关系,但是我 运行 遇到了一些现有系统动态特性的问题。一些关系是在数据库本身中定义的,这意味着 table_a
中的项目可以与任意数量的其他 table 相关,具体取决于存储的指令。
这包括 table 个存储在说明中的名称。
我当前的 objective 是找到为 table X 构建的 Eloquent Model
class。
一些注意事项:
- 为了向后兼容,我无法更改现有的数据库条目来存储 classes 而不是 table 名称。
- 因为我们的 table 名称不符合 Laravel 的命名约定,我不能假设 class 名称基于 table 名称。
- 数据库有超过 300 个 table 和超过 100 个当前用于映射指令,所以我更喜欢不需要大量 class<->table 映射的动态解决方案列出 Eloquent 模型已经在
$table
属性. 中维护的内容
也许我只是希望 Laravel 在内存中的某个地方保留所有 Eloquent classes 的清单,我可以利用它,但这可能是一厢情愿的想法。
有什么妙招吗?
根据 miken32 的建议研究反射,我能够编译样本片段并向 BaseModel 添加功能 class。这可能不是我的最终实现,但它满足了我的需要。
<?php
namespace App\Models;
use Illuminate\Container\Container;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
abstract class BaseModel extends Model
{
public static function tableName(): string
{
return with(new static)->getTable();
}
public static function getClassMetadata(): Collection
{
return Cache::rememberForever('model:eloquent:metadata',function(){
return collect(File::allFiles(app_path()))->map(function ($item){
$path = $item->getRelativePathName();
return sprintf('\%s%s', Container::getInstance()->getNamespace(),
strtr(substr($path, 0, strrpos($path, '.')), '/', '\'));
})->filter(function ($class){
$valid = false;
if (class_exists($class)) {
$reflection = new \ReflectionClass($class);
$valid = $reflection->isSubclassOf(BaseModel::class) && !$reflection->isAbstract();
}
return $valid;
})->map(function ($class){
$reflection = new \ReflectionClass($class);
return [
'fqcn' => $class,
'table' => $reflection->getMethod('tableName')->invoke(null)
];
})->values();
});
}
}
我目前正在围绕遗留数据库 Laravel/Eloquent 包装并建立关系,但是我 运行 遇到了一些现有系统动态特性的问题。一些关系是在数据库本身中定义的,这意味着 table_a
中的项目可以与任意数量的其他 table 相关,具体取决于存储的指令。
这包括 table 个存储在说明中的名称。
我当前的 objective 是找到为 table X 构建的 Eloquent Model
class。
一些注意事项:
- 为了向后兼容,我无法更改现有的数据库条目来存储 classes 而不是 table 名称。
- 因为我们的 table 名称不符合 Laravel 的命名约定,我不能假设 class 名称基于 table 名称。
- 数据库有超过 300 个 table 和超过 100 个当前用于映射指令,所以我更喜欢不需要大量 class<->table 映射的动态解决方案列出 Eloquent 模型已经在
$table
属性. 中维护的内容
也许我只是希望 Laravel 在内存中的某个地方保留所有 Eloquent classes 的清单,我可以利用它,但这可能是一厢情愿的想法。
有什么妙招吗?
根据 miken32 的建议研究反射,我能够编译样本片段并向 BaseModel 添加功能 class。这可能不是我的最终实现,但它满足了我的需要。
<?php
namespace App\Models;
use Illuminate\Container\Container;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
abstract class BaseModel extends Model
{
public static function tableName(): string
{
return with(new static)->getTable();
}
public static function getClassMetadata(): Collection
{
return Cache::rememberForever('model:eloquent:metadata',function(){
return collect(File::allFiles(app_path()))->map(function ($item){
$path = $item->getRelativePathName();
return sprintf('\%s%s', Container::getInstance()->getNamespace(),
strtr(substr($path, 0, strrpos($path, '.')), '/', '\'));
})->filter(function ($class){
$valid = false;
if (class_exists($class)) {
$reflection = new \ReflectionClass($class);
$valid = $reflection->isSubclassOf(BaseModel::class) && !$reflection->isAbstract();
}
return $valid;
})->map(function ($class){
$reflection = new \ReflectionClass($class);
return [
'fqcn' => $class,
'table' => $reflection->getMethod('tableName')->invoke(null)
];
})->values();
});
}
}