web-dev-qa-db-ja.com

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>は探しているコードです。

117
Tom Macdonald

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
155
Jarek Tkaczyk

リレーションオブジェクト は、未知のメソッド呼び出しを 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()は、Laravel(関連オブジェクトを取得する)によってマジックプロパティゲッターが設定する->relationとは対照的に、関数呼び出し(リレーションオブジェクトを取得する)です。

リレーションオブジェクトでcountメソッドを使用する(つまり、かっこを使用する)ことは、すべてのデータをプルするのではなく、カウントクエリを実行するため、$model->relation->count()またはcount($model->relation)を実行するよりもはるかに高速です(リレーションが既に読み込まれている場合を除く)データベースからの関連オブジェクト、それらを数えるためだけに。同様に、existsを使用しても、モデルデータをプルする必要はありません。

exists()count()は両方とも、私が試したすべての関係タイプで機能するため、少なくともbelongsTohasOnehasMany、およびbelongsToManyです。

61
tremby

existsメソッドを使用したい:

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

関連モデルが存在するかどうかを確認します。 Laravel 5.2では正常に動作しています

17
Hafez Divandari

Php 7.1の後、受け入れられた答えはすべてのタイプの関係に対して機能しません。

関係のタイプに応じて、EloquentはCollectionModel、またはNullを返します。そしてPhp 7.1count(null)ではerrorがスローされます。

したがって、リレーションが存在するかどうかを確認するには、次を使用できます。

単一の関係の場合:例えばhasOneおよびbelongsTo

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

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

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

Laravel 5でこれが変更されたかどうかはわかりませんが、count($data->$relation)を使用した受け入れられた答えは、リレーションプロパティにアクセスするまさにその行為が原因でロードされるため、うまくいきませんでした。

最後に、簡単なisset($data->$relation)が私のためにトリックをしました。

4
Dave Stewart

Hemerson VarelaがPhp 7.1で既に述べたように、count(null)errorをスローし、行が存在しない場合はhasOnenullを返します。 hasOnerelationがあるので、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の呼び出しを行う必要があるかどうかを判断するために、関係が存在するかどうかを確認する必要はありません。 pdateOrCreate メソッドを使用するだけです。これは上記と同等です。

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

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

2
Anthony

リレーションが既に存在するかどうかを確認したいので、updateまたはcreateを実行できます。ただし、 pdateOrCreate メソッドのため、これは必要ありません。

これを行うだけです:

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