Laravel检查是否存在相关模型

我有一个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)

2 years ago

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 years ago

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 .

2 years ago

我更喜欢使用 exists 方法:

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

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

2 years ago

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

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

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

对于单身关系:例如 hasOnebelongsTo

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

对于多个关系:例如: hasManybelongsToMany

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

2 years ago

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

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

2 years ago

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

2 years ago

正如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();
};

2 years ago

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

这样做:

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