首页 文章

Laravel检查是否存在相关模型

提问于
浏览
102

我有一个Eloquent模型,它有一个相关的模型:

public function option() {
    return $this->hasOne('RepairOption', 'repair_item_id');
}

public function setOptionArrayAttribute($values)
{
    $this->option->update($values);
}

当我创建模型时,它不一定有相关的模型 . 当我更新它时,我可能会添加一个选项 .

所以我需要检查相关模型是否存在,分别更新或创建它:

$model = RepairItem::find($id);
if (Input::has('option')) {
    if (<related_model_exists>) {
        $option = new RepairOption(Input::get('option'));
        $option->repairItem()->associate($model);
        $option->save();
        $model->fill(Input::except('option');
    } else {
       $model->update(Input::all());
    }
};

<related_model_exists> 是我要找的代码 .

8 回答

  • 6

    php 7.2+ 中,您不能在关系对象上使用 count ,因此对于所有关系都没有一个通用的方法 . 使用查询方法改为@tremby,如下所示:

    $model->relation()->exists()
    

    处理所有关系类型的通用解决方案( pre php 7.2 ):

    if (count($model->relation))
    {
      // exists
    }
    

    这将适用于每个关系,因为动态属性返回 ModelCollection . 两者都实现 ArrayAccess .

    所以它是这样的:

    single relations: hasOne / belongsTo / morphTo / morphOne

    // no related model
    $model->relation; // null
    count($model->relation); // 0 evaluates to false
    
    // there is one
    $model->relation; // Eloquent Model
    count($model->relation); // 1 evaluates to true
    

    to-many relations: hasMany / belongsToMany / morphMany / morphToMany / morphedByMany

    // no related collection
    $model->relation; // Collection with 0 items evaluates to true
    count($model->relation); // 0 evaluates to false
    
    // there are related models
    $model->relation; // Collection with 1 or more items, evaluates to true as well
    count($model->relation); // int > 0 that evaluates to true
    
  • 2

    Relation object将未知方法调用传递给Eloquent query Builder,设置为仅选择相关对象 . 那个Builder又将未知的方法调用传递给它的底层query Builder .

    这意味着您可以直接从关系对象使用exists()count()方法:

    $model->relation()->exists(); // bool: true if there is at least one row
    $model->relation()->count(); // int: number of related rows
    

    注意 relation 之后的括号: ->relation() 是一个函数调用(获取关系对象),而不是 ->relation ,这是一个由Laravel为你设置的魔法属性获取器(获取相关的对象/对象) .

    在关系对象上使用 count 方法(即使用括号)将比执行 $model->relation->count()count($model->relation) 快得多(除非关系已被急切加载),因为它运行计数查询而不是拉出所有数据来自数据库的任何相关对象,只是为了计算它们 . 同样,使用 exists 也不需要拉模型数据 .

    exists()count() 都适用于我尝试的所有关系类型,因此至少 belongsTohasOnehasManybelongsToMany .

  • 1

    我更喜欢使用 exists 方法:

    RepairItem::find($id)->option()->exists()

    检查相关模型是否存在 . 它在Laravel 5.2上运行良好

  • 0

    Php 7.1 之后,接受的答案将不适用于所有类型的关系 .

    因为根据类型的关系,Eloquent将返回 CollectionModelNull . 在 Php 7.1 count(null) 将抛出 error .

    因此,要检查关系是否存在,您可以使用:

    对于单身关系:例如 hasOnebelongsTo

    if(!is_null($model->relation)) {
       ....
    }
    

    对于多个关系:例如: hasManybelongsToMany

    if ($model->relation->isNotEmpty()) {
       ....
    }
    
  • 14

    不确定这是否在Laravel 5中有所改变,但使用 count($data->$relation) 的接受答案对我不起作用,因为访问关系属性的行为导致它被加载 .

    最后,一个直截了当的 isset($data->$relation) 为我做了伎俩 .

  • 52

    您可以在模型对象上使用relationLoaded方法 . 这节省了我的培根,希望它可以帮助别人 . 当我在Laracasts问同样的问题时,我就是given this suggestion .

  • 4

    正如Hemerson Varela在Php 7.1中已经说过 count(null) 将抛出 errorhasOne 如果没有行则返回 null . 由于你有 hasOne 关系,我会使用 empty 方法来检查:

    $model = RepairItem::find($id);
    if (!empty($temp = $request->input('option'))) {
       $option = $model->option;
    
       if(empty($option)){
          $option = $user->expertise()->create();
       }
    
       $option->someAttribute = temp;
       $option->save();
    };
    
  • 133

    你说你想检查关系是否已经存在,所以你可以做 updatecreate . 但是,由于updateOrCreate方法,这不是必需的 .

    这样做:

    $model = RepairItem::find($id);
    $model->option()
          ->updateOrCreate(['repair_item_id' => $model->id],['option' => 'A']);
    

相关问题