関連モデルが存在するかどうかのLaravelチェック


151

関連するモデルがある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>私が探しているコードはどこにありますか。


3
素晴らしい質問ありがとうございます!そして、下の人たちへの素晴らしい答え。プロジェクトの時間を節約できました。
Rafael

回答:


197

PHP 7.2+あなたが使用することはできませんcountので、すべての関係の誰も万能方法はありません、関係オブジェクトに。代わりに、以下に示す@trembyとしてクエリメソッドを使用します。

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

すべての関係タイプで動作する一般的なソリューション(php 7.2より前):

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

動的プロパティはModelor を返すため、これはすべての関係で機能します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 14

7
@CurvianVynesそうではありません。Collection独自のメソッドisEmptyがありemptyますが、ジェネリック関数はオブジェクトに対してfalseを返します(したがって、空のコレクションに対しては機能しません)。
Jarek Tkaczyk 2014年

1
count($model->relation)morphTo関係に関連付けがまだ設定されていない場合は動作しませんでした。外部IDと型はnullであり、Laravelによって作成されたdbクエリは偽であり、例外が発生します。$model->relation()->getOtherKey()回避策として使用しました。
Jocelyn

1
@Jocelynはい、それは雄弁なバグです。残念ながら、ポリモーフィック関係には少なくともいくつかありますので、明らかにそれらに依存することはできません。
Jarek Tkaczyk 14

2
それは戻って、PHP 7.2で解除されます:count(): Parameter must be an array or an object that implements Countable
CodeGodie

81

関連オブジェクトは、に至るまで、未知のメソッド呼び出しを渡し雄弁クエリビルダのみ関連するオブジェクトを選択するように設定されています、。そのBuilderは、不明なメソッド呼び出しをその基礎となるクエリ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()私が試したすべての関係タイプの作品なので、少なくともbelongsTohasOnehasMany、とbelongsToMany


ルーメンには存在しませんが、理由は不明です。
briankip 2017年

@briankip-すべきです。(magicプロパティを使用して)コレクションではなく(メソッドを呼び出して)リレーションオブジェクトを取得していることを確認しましたか?
2017年

18

私はexistsメソッドを使用することを好みます:

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

関連するモデルが存在するかどうかを確認します。Laravel 5.2では問題なく動作しています


1
+1; count($ model-> relation)は、関係テーブルにアイテムがなかったにもかかわらず、Laravel 5.2ではtrueを返していました。-> exists()がトリックを行います。
ベンウィルソン

9

のPHP 7.1、受け入れ答えは関係のすべてのタイプのために動作しません。

Eloquentはタイプの関係に応じて、a Collection、a、Modelまたはを返しNullます。そして、中にPHPの7.1 count(null)スローされますerror

したがって、関係が存在するかどうかを確認するには、次を使用できます。

単一の関係の場合:たとえばhasOnebelongsTo

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

複数の関係の場合:例:hasManyおよびbelongsToMany

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

4

これがLaravel 5で変更されたかどうかはわかりcount($data->$relation)ませんが、関係プロパティにアクセスするという行為自体がロードされるため、使用した受け入れられた回答は私にとってはうまくいきませんでした。

結局のところ、isset($data->$relation)私にとっては単純明快なトリックでした。


私はそれがあると信じてい$data->relationなくて$(編集することはできませんので、6文字の制限のため、)
Zanshin13

2
ああ$relationのようなあなたの関係の名前だろう$data->postsか、などなどです。それが混乱している場合申し訳ありませんが、私はそれはそれを明確にしたかったrelation具体的なモデルのプロパティではありませんでした:P
デイヴ・スチュワート

これはしばらくの間は機能していましたが、Laravelを5.2.29から5.2.45に更新した後は機能しなくなりました。なぜそれを修正するのか、またはどのように修正するのですか?現在、リレーショナルデータが何らかの理由で読み込まれています。
Anthony

これを修正した回答を追加しました。
Anthony

3

モデルオブジェクトでrelationLoadedメソッドを使用できます。これは私のベーコンを救ったので、うまくいけば他の誰かを助けるでしょう。私がララキャストで同じ質問をしたとき、私はこの提案与えられました。


2

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

しかし、これは不必要です。updateまたはcreate呼び出しを行う必要があるかどうかを判断するために、関係が存在するかどうかを確認する必要はありません。単にupdateOrCreateメソッドを使用します。これは上記と同等です:

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

0

count($ x)関数の使用法が悪かったため、PHPバージョンを7.2+に更新したとき、コードを完全にリファクタリングする必要がありました。これは実際の痛みであり、さまざまなシナリオで何百もの使用法があり、1つのルールがすべてに当てはまるわけではないため、非常に恐ろしいものです。

すべてをリファクタリングするために私が従った規則、例:

$ 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の投稿が非常に役立ちました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.