最佳答案
以下方法通过反射遍历并判断模型类的每一个方法返回值类型是否是Illuminate\Database\Eloquent\Relations\Relation::class
模型关联类的子类,来获取已存在的关联关系
use Illuminate\Database\Eloquent\Relations\Relation;
/**
* 获取模型的关联关系
* @param string $model
* @return array
* @throws \ReflectionException
*/
public static function getModelRelations(string $model): array
{
$methods = (new \ReflectionClass($model))->getMethods(\ReflectionMethod::IS_PUBLIC);
return array_reduce($methods, function (array $res, \ReflectionMethod $method) {
$returnType = is_null($method->getReturnType()) ? null : $method->getReturnType()->getName();
return class_exists($returnType) && (new \ReflectionClass($returnType))->isSubclassOf(Relation::class)
? [...$res, $method->getName()]
: $res;
}, []);
}
由于是通过方法的返回值类型来判定,所以必须在模型中的关联方法声明返回值的类型,否则会遗漏,如:
/**
* @return HasMany 用户列表
*/
public function users(): HasMany
{
return $this->hasMany(User::class);
}
调用结果如下:
讨论数量:
private function getAllRelations(Model $model, $heritage = 'all')
{
$modelName = get_class($model);
$types = ['children' => 'Has', 'parents' => 'Belongs', 'all' => ''];
$heritage = in_array($heritage, array_keys($types)) ? $heritage : 'all';
$reflectionClass = new \ReflectionClass($model);
$traits = $reflectionClass->getTraits();
$traitMethodNames = [];
foreach ($traits as $name => $trait) {
$traitMethods = $trait->getMethods();
foreach ($traitMethods as $traitMethod) {
$traitMethodNames[] = $traitMethod->getName();
}
}
$currentMethod = collect(explode('::', __METHOD__))->last();
$filter = $types[$heritage];
$methods = $reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC);
$methods = collect($methods)->filter(function ($method) use ($modelName, $traitMethodNames, $currentMethod) {
$methodName = $method->getName();
if (!in_array($methodName, $traitMethodNames)
&& strpos($methodName, '__') !== 0
&& $method->class === $modelName
&& !$method->isStatic()
&& $methodName != $currentMethod
) {
$parameters = (new ReflectionMethod($modelName, $methodName))->getParameters();
return collect($parameters)->filter(function ($parameter) {
return !$parameter->isOptional();
})->isEmpty();
}
return false;
})->mapWithKeys(function ($method) use ($model, $filter) {
$methodName = $method->getName();
$relation = $model->$methodName();
if (is_subclass_of($relation, Relation::class)) {
$type = (new ReflectionClass($relation))->getShortName();
if (!$filter || strpos($type, $filter) === 0) {
return [$methodName => ['class' => get_class($relation->getRelated()), 'relation' => get_class($relation) ] ];
}
}
return [];
})->toArray();
return $methods;
}
以下方法通过反射遍历并判断模型类的每一个方法返回值类型是否是Illuminate\Database\Eloquent\Relations\Relation::class
模型关联类的子类,来获取已存在的关联关系
use Illuminate\Database\Eloquent\Relations\Relation;
/**
* 获取模型的关联关系
* @param string $model
* @return array
* @throws \ReflectionException
*/
public static function getModelRelations(string $model): array
{
$methods = (new \ReflectionClass($model))->getMethods(\ReflectionMethod::IS_PUBLIC);
return array_reduce($methods, function (array $res, \ReflectionMethod $method) {
$returnType = is_null($method->getReturnType()) ? null : $method->getReturnType()->getName();
return class_exists($returnType) && (new \ReflectionClass($returnType))->isSubclassOf(Relation::class)
? [...$res, $method->getName()]
: $res;
}, []);
}
由于是通过方法的返回值类型来判定,所以必须在模型中的关联方法声明返回值的类型,否则会遗漏,如:
/**
* @return HasMany 用户列表
*/
public function users(): HasMany
{
return $this->hasMany(User::class);
}
调用结果如下:
推荐文章: