Periksa Laravel Jika Model Terkait Ada

151

Saya memiliki model Eloquent yang memiliki model terkait:

public function option() {
    return $this->hasOne('RepairOption', 'repair_item_id');
}

public function setOptionArrayAttribute($values)
{
    $this->option->update($values);
}

Ketika saya membuat model, itu tidak harus memiliki model terkait. Ketika saya memperbaruinya, saya mungkin menambahkan opsi, atau tidak.

Jadi saya perlu memeriksa apakah model terkait ada, untuk memperbaruinya, atau membuatnya masing-masing:

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

Di mana <related_model_exists>kode yang saya cari.

Tom Macdonald
sumber
3
Pertanyaan yang luar biasa terima kasih! Dan jawaban yang bagus untuk orang-orang di bawah ini. Menghemat waktu saya di proyek saya.
Rafael

Jawaban:

197

Di php 7.2+ Anda tidak bisa menggunakan countobjek relasi, jadi tidak ada metode satu-cocok-semua untuk semua relasi. Gunakan metode kueri sebagai ganti @tremby yang disediakan di bawah ini:

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

solusi umum yang bekerja pada semua tipe relasi ( pre php 7.2 ):

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

Ini akan berfungsi untuk setiap relasi karena properti dinamis kembali Modelatau Collection. Keduanya menerapkan ArrayAccess.

Jadi begini:

hubungan tunggal: 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

ke-banyak hubungan: 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
Jarek Tkaczyk
sumber
1
Baca semuanya. count($relation)adalah solusi umum untuk semua hubungan. Ini akan bekerja untuk Modeldan Collection, sementara Modeltidak memiliki ->count()metode.
Jarek Tkaczyk
7
@CurvianVynes Tidak, tidak. Collectionmemiliki metode sendiri isEmpty, tetapi emptyfungsi generik mengembalikan false untuk objek (sehingga tidak akan berfungsi untuk koleksi kosong).
Jarek Tkaczyk
1
count($model->relation)tidak berfungsi morphToketika hubungan belum memiliki hubungan yang ditetapkan. ID dan jenis asing adalah nol dan kueri db yang dibuat oleh Laravel adalah palsu dan muncul pengecualian. Saya digunakan $model->relation()->getOtherKey()sebagai solusi.
Jocelyn
1
@Jocelyn Ya, ini adalah bug Eloquent. Sayangnya ada setidaknya beberapa dari mereka untuk hubungan polimorfik, jadi jelas Anda tidak dapat mengandalkan mereka dengan cara apa pun.
Jarek Tkaczyk
2
Ini akan count(): Parameter must be an array or an object that implements Countable
berhenti
81

Sebuah objek Hubungan melewati metode panggilan yang tidak dikenal melalui sebuah fasih permintaan Builder , yang dibentuk untuk hanya memilih obyek terkait. Itu Builder pada gilirannya melewati metode yang tidak diketahui panggilan melalui nya yang mendasari permintaan Builder .

Ini berarti Anda dapat menggunakan metode exists()atau count()langsung dari objek relasi:

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

Perhatikan tanda kurung setelah relation: ->relation()adalah pemanggilan fungsi (mendapatkan objek relasi), yang berlawanan dengan ->relationyang ditetapkan pengambil properti sihir untuk Anda oleh Laravel (mendapatkan objek / objek terkait).

Menggunakan countmetode pada objek relasi (yaitu, menggunakan tanda kurung) akan jauh lebih cepat daripada melakukan $model->relation->count()atau count($model->relation)(kecuali relasi telah dimuat dengan penuh semangat) karena menjalankan kueri hitung daripada menarik semua data untuk objek terkait dari basis data, hanya untuk menghitungnya. Demikian juga, menggunakan existstidak perlu menarik data model juga.

Kedua exists()dan count()bekerja pada semua jenis hubungan saya sudah mencoba, jadi setidaknya belongsTo, hasOne, hasMany, dan belongsToMany.

gemetar
sumber
ada tidak tersedia di lumen, tidak yakin mengapa.
briankip
@ Briankip - seharusnya begitu. Anda yakin mendapatkan objek relasi (dengan memanggil metode) daripada koleksi (dengan menggunakan properti ajaib)?
gemetar
18

Saya lebih suka menggunakan existsmetode:

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

untuk memeriksa apakah model terkait ada atau tidak. Ini berfungsi dengan baik di Laravel 5.2

Hafez Divandari
sumber
1
+1; count ($ model-> relation) mengembalikan nilai true untuk saya di Laravel 5.2 meskipun tidak ada item dalam tabel relasi. -> exist () melakukan trik.
Ben Wilson
9

Setelah Php 7.1 , Jawaban yang diterima tidak akan berfungsi untuk semua jenis hubungan.

Karena tergantung dari jenis hubungannya, Eloquent akan mengembalikan a Collection, a Modelatau Null. Dan dalam Php 7.1 count(null) akan melemparerror .

Jadi, untuk memeriksa apakah hubungan itu ada, Anda dapat menggunakan:

Untuk hubungan tunggal: Misalnya hasOnedanbelongsTo

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

Untuk hubungan berganda: Sebagai Contoh: hasManydanbelongsToMany

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

Tidak yakin apakah ini telah berubah di Laravel 5, tetapi jawaban yang diterima menggunakan count($data->$relation) tidak berfungsi untuk saya, karena tindakan mengakses properti relasi menyebabkannya dimuat.

Pada akhirnya, saya langsung isset($data->$relation)melakukan trik.

Dave Stewart
sumber
Saya percaya ini $data->relationtanpa $(tidak dapat diedit, karena batas 6 karakter)
Zanshin13
2
Ah itu $relationakan menjadi nama hubungan Anda, seperti $data->postsatau sejenisnya. Maaf jika itu membingungkan, saya ingin menjelaskan bahwa relationitu bukan model properti yang konkret: P
Dave Stewart
Ini berfungsi untuk sementara, tetapi berhenti bekerja setelah saya memperbarui Laravel dari 5.2.29 ke 5.2.45. Adakah yang tahu mengapa atau bagaimana cara memperbaikinya? Sekarang menyebabkan data relasional dimuat karena suatu alasan.
Anthony
Saya menambahkan jawaban yang memiliki perbaikan untuk ini.
Anthony
3

Anda dapat menggunakan metode relationLoaded pada objek model. Ini menyelamatkan daging saya jadi mudah-mudahan ini membantu orang lain. Saya diberi saran ini ketika saya mengajukan pertanyaan yang sama pada Laracasts.

Anthony
sumber
2

Seperti yang sudah dikatakan Hemerson Varela di Php 7.1 count(null)akan melempar errordan hasOnekembali nulljika tidak ada baris. Karena Anda memiliki hasOnerelasi, saya akan menggunakan emptymetode ini untuk memeriksa:

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

Tapi ini berlebihan. Tidak perlu memeriksa apakah hubungannya ada, untuk menentukan apakah Anda harus melakukan updateatau createpanggilan. Cukup gunakan metode updateOrCreate . Ini sama dengan di atas:

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

Saya harus sepenuhnya memperbaiki kode saya ketika saya memperbarui versi PHP saya ke 7.2+ karena penggunaan fungsi count ($ x) yang buruk. Ini adalah rasa sakit yang nyata dan juga sangat menakutkan karena ada ratusan penggunaan, dalam skenario yang berbeda dan tidak ada aturan yang cocok untuk semua ..

Aturan yang saya ikuti untuk memperbaiki semuanya, contoh:

$ x = Auth :: user () -> posts-> find (6); (periksa apakah pengguna memiliki kiriman id = 6 menggunakan -> find ())

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

$ x = Auth :: user () -> profile-> department; (periksa apakah profil memiliki beberapa departemen, mungkin ada banyak departemen)

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

$ x = Auth :: user () -> profile-> get (); (periksa apakah pengguna memiliki profil setelah menggunakan -> get ())

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

Berharap ini dapat membantu, bahkan 5 tahun setelah pertanyaan diajukan, posting stackoverflow ini telah banyak membantu saya!

raphjutras
sumber