我有一个具有相关模型的 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>
是我要查找的代码。
在 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
Relation object 将未知方法调用传递给 Eloquent query Builder,该 Eloquent query Builder 设置为仅选择相关对象。该 Builder 反过来将未知方法调用传递给 its 底层 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 为您设置的魔法属性 getter(获取相关对象/对象)。
在关系对象上使用 count
方法(即使用括号)将比使用 $model->relation->count()
或 count($model->relation)
快得多(除非关系已经预先加载),因为它运行计数查询而不是从数据库中提取任何相关对象的所有数据,只是为了计算它们。同样,使用 exists
也不需要提取模型数据。
exists()
和 count()
都适用于我尝试过的所有关系类型,因此至少有 belongsTo
、hasOne
、hasMany
和 belongsToMany
。
exists
不适用于不存在的 morphTo
关系。它得到一个 SQL 错误。
exists()
和 count()
要求相关模型已保存在数据库中。如果您需要在保存相关模型之前检查是否存在(例如,如果您使用了 setRelation),那么您应该使用 is_null
或 empty
。
我更喜欢使用 exists
方法:
RepairItem::find($id)->option()->exists()
检查相关模型是否存在。它在 Laravel 5.2 上运行良好
在 PHP 7.1 之后,接受的答案将不适用于所有类型的关系。
因为根据关系的类型,Eloquent 将返回 Collection
、Model
或 Null
。而在 Php 7.1 中,count(null)
会抛出一个 error
。
因此,要检查关系是否存在,您可以使用:
对于单一关系:例如 hasOne
和 belongsTo
if(!is_null($model->relation)) {
....
}
对于多个关系:例如:hasMany
和 belongsToMany
if ($model->relation->isNotEmpty()) {
....
}
正如 Hemerson Varela 在 Php 7.1 中所说,count(null)
将抛出 error
,如果不存在行,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]);
}
不确定这是否在 Laravel 5 中发生了变化,但使用 count($data->$relation)
接受的答案对我不起作用,因为访问关系属性的行为导致它被加载。
最后,一个简单的 isset($data->$relation)
为我解决了问题。
$
的 $data->relation
(由于 6 个字符的限制,无法编辑)
$relation
将是您的关系名称,例如 $data->posts
或类似的名称。抱歉,如果这令人困惑,我想明确指出 relation
不是具体的模型属性:P
Model::__isset
方法被重载,即使没有相关实体它也会返回 true。您需要使用 !is_null
来避免神奇的 isset
逻辑。他们已经确认这是 Laravel 中的一个已知错误,将在 Laravel 8 中修复:github.com/laravel/framework/issues/31793
我用于单一关系:hasOne
、belongsTo
和 morphs
if($model->relation){
....
}
因为如果条件为空,这将是错误的。
对于多个关系:hasMany
、belongsToMany
和 morphs
if ($model->relation->isNotEmpty()) {
....
}
当我将我的 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 帖子也对我有很大帮助!
如果您使用模型类并使用 Eloquent ORM,则创建一个新方法并返回 bool 数据。喜欢
public function hasPosts(): bool
{
return $this->posts()->exists();
}
不定期副业成功案例分享
count($relation)
是所有关系的通用解。它适用于Model
和Collection
,而Model
没有->count()
方法。Collection
有自己的方法isEmpty
,但通用empty
函数对对象返回 false(因此不适用于空集合)。count($model->relation)
在morphTo
上不起作用。外部 id 和 type 为 null 并且 Laravel 构建的 db 查询是伪造的并引发异常。我使用$model->relation()->getOtherKey()
作为解决方法。count(): Parameter must be an array or an object that implements Countable