Kiểm tra Laravel nếu mô hình liên quan tồn tại


151

Tôi có một mô hình Eloquent có một mô hình liên quan:

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

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

Khi tôi tạo mô hình, nó không nhất thiết phải có một mô hình liên quan. Khi tôi cập nhật nó, tôi có thể thêm một tùy chọn hoặc không.

Vì vậy, tôi cần kiểm tra xem mô hình liên quan có tồn tại hay không, để cập nhật nó hoặc tạo ra nó, tương ứng:

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

Trong trường hợp <related_model_exists>là mã Tôi đang tìm kiếm.


3
Câu hỏi tuyệt vời cảm ơn bạn! Và câu trả lời tuyệt vời cho những kẻ dưới đây. Tiết kiệm thời gian cho dự án của tôi.
Rafael

Câu trả lời:


197

Trong php 7.2+, bạn không thể sử dụng counttrên đối tượng quan hệ, vì vậy không có phương thức ai phù hợp cho tất cả các mối quan hệ. Sử dụng phương thức truy vấn thay vì @tremby được cung cấp dưới đây:

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

giải pháp chung làm việc trên tất cả các loại quan hệ ( trước php 7.2 ):

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

Điều này sẽ làm việc cho mọi mối quan hệ kể từ khi thuộc tính động trở lại Modelhoặc Collection. Cả hai thực hiện ArrayAccess.

Vì vậy, nó đi như thế này:

quan hệ đơn lẻ: 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

quan hệ nhiều người: 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
Đọc toàn bộ. count($relation)là một giải pháp chung cho tất cả các mối quan hệ. Nó sẽ làm việc cho ModelCollection, trong khi Modelkhông có ->count()phương pháp.
Jarek Tkachot

7
@CurvianVynes Không, không. Collectioncó phương thức riêng isEmpty, nhưng emptyhàm chung trả về false cho một đối tượng (do đó sẽ không hoạt động đối với bộ sưu tập trống).
Jarek Tkachot

1
count($model->relation)đã không làm việc morphTokhi mối quan hệ chưa có mối quan hệ nào được thiết lập. Id và kiểu nước ngoài là null và truy vấn db được xây dựng bởi Laravel là không có thật và làm tăng ngoại lệ. Tôi đã sử dụng $model->relation()->getOtherKey()như một cách giải quyết.
Jocelyn

1
@Jocelyn Vâng, đó là lỗi Eloquent. Thật không may, có ít nhất một vài trong số chúng cho các mối quan hệ đa hình, vì vậy rõ ràng bạn không thể dựa vào chúng theo bất kỳ cách nào.
Jarek Tkachot

2
Nó sẽ bị count(): Parameter must be an array or an object that implements Countable
hỏng

81

Một đối tượng Relation chuyển các lệnh gọi phương thức không xác định đến Trình tạo truy vấn Eloquent , được thiết lập để chỉ chọn các đối tượng liên quan. Trình dựng đó lần lượt chuyển các cuộc gọi phương thức không xác định đến Trình tạo truy vấn cơ bản của nó .

Điều này có nghĩa là bạn có thể sử dụng exists()hoặc count()các phương thức trực tiếp từ một đối tượng quan hệ:

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

Lưu ý các dấu ngoặc đơn sau relation: ->relation()là một lệnh gọi hàm (lấy đối tượng quan hệ), trái ngược với ->relationđiều mà một trình thu thập thuộc tính ma thuật được thiết lập cho bạn bởi Laravel (nhận các đối tượng / đối tượng liên quan).

Sử dụng countphương thức trên đối tượng quan hệ (nghĩa là sử dụng dấu ngoặc đơn) sẽ nhanh hơn nhiều so với thực hiện $model->relation->count()hoặc count($model->relation)(trừ khi mối quan hệ đã được tải háo hức) vì nó chạy truy vấn đếm thay vì kéo tất cả dữ liệu cho bất kỳ đối tượng liên quan nào từ cơ sở dữ liệu, chỉ để đếm chúng. Tương tự như vậy, sử dụng existskhông cần phải kéo dữ liệu mô hình.

Cả hai exists()count()làm việc trên tất cả các loại mối quan hệ tôi đã cố gắng, vì vậy ít nhất belongsTo, hasOne, hasMany, và belongsToMany.


tồn tại là không có sẵn trong lòng, không biết tại sao.
briankip

@briankip - nên. Bạn có chắc chắn bạn đang nhận được đối tượng quan hệ (bằng cách gọi phương thức) thay vì bộ sưu tập (bằng cách sử dụng thuộc tính ma thuật)?
run rẩy

18

Tôi thích sử dụng existsphương pháp:

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

để kiểm tra xem mô hình liên quan có tồn tại hay không. Nó hoạt động tốt trên Laravel 5.2


1
+1; số đếm ($ model-> mối quan hệ) đã trở lại đúng với tôi trong Laravel 5.2 mặc dù không có mục nào trong bảng quan hệ. -> tồn tại () thực hiện các mẹo.
Ben Wilson

9

Sau Php 7.1 , câu trả lời được chấp nhận sẽ không hoạt động cho tất cả các loại mối quan hệ.

Bởi vì tùy thuộc vào loại mối quan hệ, Eloquent sẽ trả về a Collection, a Modelhoặc Null. Và trong Php 7.1 count(null) sẽ ném một error.

Vì vậy, để kiểm tra xem mối quan hệ có tồn tại hay không, bạn có thể sử dụng:

Đối với các mối quan hệ duy nhất: Ví dụ hasOnebelongsTo

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

Đối với nhiều mối quan hệ: Ví dụ: hasManybelongsToMany

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

4

Không chắc điều này có thay đổi trong Laravel 5 không, nhưng câu trả lời được chấp nhận sử dụng count($data->$relation)không có tác dụng với tôi, vì chính hành động truy cập vào thuộc tính quan hệ đã khiến nó được tải.

Cuối cùng, một người đơn giản isset($data->$relation)đã lừa tôi.


Tôi tin rằng nó $data->relationkhông có $(không thể chỉnh sửa, vì giới hạn 6 ký tự)
Zanshin13

2
Ah $relationsẽ là tên của mối quan hệ của bạn, chẳng hạn như $data->postshoặc như thế. Xin lỗi nếu điều đó gây nhầm lẫn, tôi muốn làm rõ rằng đó relationkhông phải là một tài sản mô hình cụ thể: P
Dave Stewart

Điều này đã hoạt động được một thời gian, nhưng nó đã ngừng hoạt động sau khi tôi cập nhật Laravel từ 5.2,29 lên 5.2,45. Bất kỳ ý tưởng tại sao hoặc làm thế nào để sửa chữa nó? Bây giờ nó làm cho dữ liệu quan hệ được tải vì một số lý do.
Anthony

Tôi đã thêm một câu trả lời có một sửa chữa cho điều này.
Anthony

3

Bạn có thể sử dụng phương thức quan hệ được tải trên đối tượng mô hình. Điều này đã cứu thịt xông khói của tôi vì vậy hy vọng nó sẽ giúp người khác. Tôi đã được gợi ý này khi tôi hỏi cùng một câu hỏi trên Laracasts.


2

Như Hemerson Varela đã nói trong Php 7.1 count(null)sẽ ném errorhasOnetrả lại nullnếu không có hàng nào tồn tại. Vì bạn có hasOnequan hệ nên tôi sẽ sử dụng emptyphương pháp để kiểm tra:

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

Nhưng điều này là thừa. Không cần kiểm tra xem mối quan hệ có tồn tại hay không, để xác định xem bạn nên thực hiện updatemột createcuộc gọi hay. Đơn giản chỉ cần sử dụng phương thức updateOrCreate . Điều này tương đương với ở trên:

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

0

Tôi đã phải cấu trúc lại hoàn toàn mã của mình khi tôi cập nhật phiên bản PHP của mình lên 7.2+ do sử dụng sai hàm đếm ($ x). Đây là một nỗi đau thực sự và nó cũng cực kỳ đáng sợ khi có hàng trăm cách sử dụng, trong các tình huống khác nhau và không có quy tắc nào phù hợp với tất cả ..

Quy tắc tôi tuân theo để cấu trúc lại mọi thứ, ví dụ:

$ x = Auth :: user () -> bài viết-> find (6); (kiểm tra xem người dùng có id bài đăng = 6 bằng cách sử dụng -> find ())

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

$ x = Auth :: user () -> profile-> các phòng ban; (kiểm tra xem hồ sơ có một số phòng ban, có thể có nhiều phòng ban)

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

$ x = Auth :: user () -> hồ sơ-> get (); (kiểm tra xem người dùng có hồ sơ sau khi sử dụng -> get ())

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

Hy vọng điều này có thể giúp ích, thậm chí 5 năm sau khi câu hỏi được hỏi, bài đăng stackoverflow này đã giúp tôi rất nhiều!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.