Laravel检查相关模型是否存在


151

我有一个口才的模型,其中有一个相关的模型:

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>我要查找的代码在哪里。


3
很棒的问题,谢谢!和下面的家伙很好的答案。为我节省了时间。
拉斐尔

Answers:


197

php 7.2+中,您不能count在关系对象上使用,因此对于所有关系都没有一种万能的方法。使用查询方法代替@tremby,如下所示:

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

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

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

由于动态属性返回Model或,因此这将适用于每个关系Collection。两者都实现ArrayAccess

所以它是这样的:

单一的关系: 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

一对多关系: 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

1
阅读整件事。count($relation)是解决所有关系的通用解决方案。它适用于ModelCollection,但Model没有->count()方法。
Jarek Tkaczyk 2014年

7
@CurvianVynes不,不是。Collection有自己的方法isEmpty,但是泛型empty函数对一个对象返回false(因此对空集合不起作用)。
Jarek Tkaczyk 2014年

1
count($model->relation)morphTo当关系还没有建立关联时,它就不起作用了。外部ID和类型为null,Laravel构建的db查询是虚假的,并引发异常。我用作$model->relation()->getOtherKey()解决方法。
Jocelyn 2014年

1
@Jocelyn是的,这是雄辩的错误。不幸的是,至少有一些用于多态关系,因此显然您不能以任何方式依赖它们。
Jarek Tkaczyk

2
它将在PHP 7.2上中断,返回:count(): Parameter must be an array or an object that implements Countable
CodeGodie

81

Relation对象穿过一个未知的方法调用口才查询生成器,其被设置为仅选择相关对象。该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()是一个函数调用(获取关系对象),->relation与之相反,Laravel为您设置了一个魔术属性获取器(获取相关的一个或多个对象)。

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

无论exists()count()工作在我已经尝试了所有关系类型,所以至少belongsTohasOnehasMany,和belongsToMany


在管腔中不存在,不确定为什么。
briankip

@briankip-应该。您确定要获取关系对象(通过调用方法)而不是集合(通过使用magic属性)吗?
tremby

18

我更喜欢使用exists方法:

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

检查相关模型是否存在。在Laravel 5.2上工作正常


1
+1; 在Laravel 5.2中,count($ model-> relation)对我返回true,即使在关系表中没有项目。-> exists()可以解决问题。
本·威尔逊

9

之后的PHP 7.1,接受的答案将不是对所有类型的关系的工作。

因为根据类型的关系,Eloquent将返回a Collection,a ModelNull。并且在php 7.1中 count(null)会抛出一个error

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

对于单一关系:例如hasOnebelongsTo

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

对于多个关系:例如:hasManybelongsToMany

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

4

不知道这在Laravel 5中是否已更改,但是使用接受的答案count($data->$relation)对我而言不起作用,因为访问Relation属性的行为实际上导致它被加载。

最后,一个简单isset($data->$relation)的技巧对我有用。


我相信它是$data->relation没有的$(由于6个字符的限制,因此无法编辑)
Zanshin13 2013年

2
啊,那$relation将是您的关系的名称,例如$data->posts或之类的。抱歉,如果这令人困惑,我想表明这relation不是具体的模型属性:P
Dave Stewart

这工作了一段时间,但是在我将Laravel从5.2.29更新到5.2.45之后,它停止了工作。任何想法为什么或如何解决?现在由于某种原因导致关系数据被加载。
安东尼

我添加了一个对此有修复的答案。
安东尼


2

正如Hemerson Varela在php 7.1中已经说过count(null)error,如果不存在任何行,将抛出an 并hasOne返回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();
};

但这是多余的。无需检查该关系是否存在,而无需确定您应该进行呼叫update还是create呼叫。只需使用updateOrCreate方法。这等效于以上内容:

$model = RepairItem::find($id);
if (!empty($temp = $request->input('option'))) {  
   $model->option()
         ->updateOrCreate(['repair_item_id' => $model->id],
                          ['option' => $temp]);
}

0

当我将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->部门;(检查个人资料是否有部门,可以有很多部门)

[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帖子也对我有很大帮助!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.