不存在的模型类的雄辩关系

Mar*_*łek 2 laravel eloquent laravel-5

我想在我的应用程序中有许多模型/模块,但有些客户端会删除它们中的一些.

现在我有这样的关系:

public function people()
{
    return $this->hasMany('People', 'model_id');
}
Run Code Online (Sandbox Code Playgroud)

当我运行$model = Model::with('people')->get();它工作正常

但如果People模型不存在怎么办?

目前我得到了:

ClassLoader.php第386行中的1/1 ErrorException:include(...):无法打开流:没有这样的文件或目录

我试过了

public function people()
{ 
    try {
       return $this->hasMany('People', 'model_id');
    }
    catch (FatalErrorException $e) {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

或者:

public function people()
{ 
    return null; // here I could add checking if there is a Model class and if not return null
}
Run Code Online (Sandbox Code Playgroud)

但是使用这种方法时$model = Model::with('people')->get();不起作用.

我将有几十个关系,我不能列出它们用于with.最好的方法是使用一些empty relation(返回null)只是为了使Eloquent不做任何事情,但在这种情况下,Eloquent仍然试图让它工作,我会得到:

哎呀,看起来像出事了.Builder.php第430行中的1/1 FatalErrorException:在null上调用成员函数addEagerConstraints()

那有什么简单的解决方案吗?

luk*_*ter 7

我能提出的唯一解决方案是创建自己的Eloquent\Builder类.

我打电话给它MyBuilder.让我们首先确保它实际使用.在您的模型中(最好是基本模型)添加此newEloquentBuilder方法:

public function newEloquentBuilder($query)
{
    return new MyBuilder($query);
}
Run Code Online (Sandbox Code Playgroud)

在自定义Builder类中,我们将覆盖该loadRelation方法并在关系上调用if null之前添加一个检查addEagerConstraints(或者在您的情况下null)

class MyBuilder extends \Illuminate\Database\Eloquent\Builder {
    protected function loadRelation(array $models, $name, Closure $constraints)
    {
        $relation = $this->getRelation($name);


        if($relation == null){
            return $models;
        }


        $relation->addEagerConstraints($models);

        call_user_func($constraints, $relation);

        $models = $relation->initRelation($models, $name);

        $results = $relation->getEager();

        return $relation->match($models, $results, $name);
    }
}
Run Code Online (Sandbox Code Playgroud)

该函数的其余部分基本上与原始构建器(Illuminate\Database\Eloquent\Builder)中的代码完全相同

现在只需在关系函数中添加这样的东西,它应该全部工作:

public function people()
{
    if(!class_exist('People')){
        return null;
    }
    return $this->hasMany('People', 'model_id');
}
Run Code Online (Sandbox Code Playgroud)

更新:关系一样使用它

如果你想像关系一样使用它,它会变得有点棘手.

您必须覆盖该getRelationshipFromMethod功能Eloquent\Model.所以让我们创建一个基础模型(你的模型显然需要扩展它......)

class BaseModel extends \Illuminate\Database\Eloquent\Model {
    protected function getRelationshipFromMethod($key, $camelKey)
    {
        $relations = $this->$camelKey();

        if ( $relations instanceof \Illuminate\Database\Eloquent\Collection){
            // "fake" relationship
            return $this->relations[$key] = $relations;
        }
        if ( ! $relations instanceof Relation)
        {
            throw new LogicException('Relationship method must return an object of type '
                . 'Illuminate\Database\Eloquent\Relations\Relation');
        }

        return $this->relations[$key] = $relations->getResults();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们需要修改关系以返回空集合

public function people()
{
    if(!class_exist('People')){
        return new \Illuminate\Database\Eloquent\Collection();
    }
    return $this->hasMany('People', 'model_id');
}
Run Code Online (Sandbox Code Playgroud)

并更改loadRelation函数MyBuilder以检查类型集合而不是null

protected function loadRelation(array $models, $name, Closure $constraints)
{
    $relation = $this->getRelation($name);

    if($relation instanceof \Illuminate\Database\Eloquent\Collection){
        return $models;
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)