175

我有一个具有相关模型的 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>我要找的代码在哪里。

4

10 回答 10

252

php 7.2+ 中,您不能count在关系对象上使用,因此没有适用于所有关系的万能方法。改用查询方法,如下面提供的@tremby:

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

适用于所有关系类型的通用解决方案(php 7.2 之前):

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

这将适用于每个关系,因为动态属性返回Modelor Collection。两者都实施ArrayAccess

所以它是这样的:

单身 关系:hasOne///belongsTomorphTomorphOne

// 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

关系:hasMany////belongsToManymorphManymorphToManymorphedByMany

// 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
于 2014-05-28T12:45:19.420 回答
94

Relation 对象将未知的方法调用传递给Eloquent 查询构建器,该查询构建器设置为仅选择相关对象。该 Builder 反过来将未知的方法调用传递给底层查询 Builder

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

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

relation注意:后面的括号->relation()是一个函数调用(获取关系对象),而不是->relationLaravel 为您设置的魔法属性 getter(获取相关对象/对象)。

在关系对象上使用count方法(即使用括号)将比做$model->relation->count()count($model->relation)(除非关系已经预先加载)快得多,因为它运行计数查询而不是提取任何相关对象的所有数据从数据库中,只是为了计算它们。同样, usingexists也不需要提取模型数据。

两者都exists()适用count()于我尝试过的所有关系类型,所以至少belongsTo, hasOne,hasManybelongsToMany.

于 2015-06-23T23:41:43.260 回答
20

我更喜欢使用exists方法:

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

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

于 2016-06-11T18:43:13.810 回答
15

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

因为根据关系的类型,Eloquent 将返回 a Collection、 aModelNull。在PHP 7.1 count(null)中会抛出一个error.

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

对于单身关系:例如hasOnebelongsTo

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

对于多重关系:例如:hasManybelongsToMany

if ($model->relation->isNotEmpty()) {
   ....
}
于 2018-03-02T23:46:29.710 回答
4

您可以在模型对象上使用relationLoaded方法。这救了我的培根,所以希望它可以帮助别人。当我在 Laracasts 上问同样的问题时,我得到了这个建议。

于 2016-10-26T07:12:09.543 回答
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 = $model->option()->create();
   }

   $option->someAttribute = temp;
   $option->save();
};

但这是多余的。无需检查关系是否存在,以确定您是否应该进行通话updatecreate通话。只需使用updateOrCreate方法。这相当于上面的:

$model = RepairItem::find($id);
if (!empty($temp = $request->input('option'))) {  
   $model->option()
         ->updateOrCreate(['repair_item_id' => $model->id],
                          ['option' => $temp]);
}
于 2018-04-26T12:29:11.313 回答
3

不确定这是否在 Laravel 5 中发生了变化,但接受的答案 usingcount($data->$relation)对我不起作用,因为访问关系属性的行为导致它被加载。

最后,一个直截了当isset($data->$relation)的方法对我有用。

于 2016-03-01T01:40:41.017 回答
3

我用于单一关系hasOnebelongsTomorphs

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

因为如果条件为空,这将是错误的。

对于多个关系hasManybelongsToManymorphs

if ($model->relation->isNotEmpty()) {
   ....
}
于 2021-09-08T06:46:26.640 回答
1

当我将我的 PHP 版本更新到 7.2+ 时,我不得不完全重构我的代码,因为 count($x) 函数使用不当。这是一个真正的痛苦,也非常可怕,因为有数百种用法,在不同的场景中,没有一个规则适合所有..

我遵循的规则来重构一切,例如:

$x = Auth::user()->posts->find(6); (使用 ->find() 检查用户是否有帖子 id=6)

[FAILS] if(count($x)) { return 'Found'; } 
[GOOD] if($x) { return 'Found'; }

$x = Auth::user()->profile->departments; (检查配置文件是否有一些部门,可以有很多部门)

[FAILS] if(count($x)) { return 'Found'; }
[GOOD] if($x->count()) { return 'Found'; }

$x = Auth::user()->profile->get(); (使用 ->get() 后检查用户是否有个人资料)

[FAILS] if(count($x)) { return 'Found'; }
[GOOD] if($x->count()) { return 'Found'; }

希望这能有所帮助,即使在提出问题 5 年后,这篇 stackoverflow 帖子也对我有很大帮助!

于 2020-04-10T14:04:48.093 回答
0

如果您使用模型类并使用 Eloquent ORM,则创建一个新方法并返回 bool 数据。像

public function hasPosts(): bool
{
    return $this->posts()->exists();
}
于 2021-08-04T13:36:06.880 回答