ตรวจสอบ 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
}

นี้จะทำงานสำหรับทุกความสัมพันธ์ตั้งแต่คุณสมบัติแบบไดนามิกกลับหรือModel ทั้งสองใช้CollectionArrayAccess

ดังนั้นมันจะเป็นเช่นนี้:

ความสัมพันธ์เดียว: 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)เป็นทางออกทั่วไปสำหรับความสัมพันธ์ทั้งหมด มันจะทำงานได้ModelและCollectionในขณะที่Modelไม่มี->count()วิธี
Jarek Tkaczyk

7
@CurvianVynes ไม่มันไม่ได้ CollectionมีวิธีการของตัวเองisEmptyแต่emptyฟังก์ชั่นทั่วไปส่งกลับเท็จสำหรับวัตถุ (ดังนั้นจะไม่ทำงานสำหรับคอลเลกชันที่ว่างเปล่า)
Jarek Tkaczyk

1
count($model->relation)ไม่ทำงานmorphToเมื่อความสัมพันธ์ยังไม่มีการตั้งค่าความสัมพันธ์ Foreign id และ type เป็นโมฆะและ db db ที่สร้างโดย Laravel นั้นเป็นของปลอมและมีข้อยกเว้นเพิ่มขึ้น ฉันใช้$model->relation()->getOtherKey()เป็นวิธีแก้ปัญหา
โจเซลีน

1
@ โจเซลีนใช่มันเป็นข้อบกพร่องที่พูดเกินจริง น่าเสียดายที่มีอย่างน้อยสองสามคนที่มีความสัมพันธ์แบบ polymorphic ดังนั้นคุณจึงไม่สามารถไว้ใจได้
Jarek Tkaczyk

2
มันจะหยุดลงใน PHP 7.2 และส่งคืน:count(): Parameter must be an array or an object that implements Countable
CodeGodie

81

วัตถุสัมพันธ์ผ่านการโทรที่ไม่รู้จักวิธีการผ่านไปยังฝีปากสร้างแบบสอบถามซึ่งการตั้งค่าให้เลือกเฉพาะวัตถุที่เกี่ยวข้อง ที่สร้างในทางกลับกันผ่านสายที่ไม่รู้จักวิธีการผ่านไปของต้นแบบสร้างแบบสอบถาม

ซึ่งหมายความว่าคุณสามารถใช้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 ตั้งค่าเวทมนตร์ให้คุณโดย Laravel (การรับวัตถุ / วัตถุที่เกี่ยวข้อง)

การใช้countวิธีการบนวัตถุความสัมพันธ์ (นั่นคือการใช้วงเล็บ) จะเร็วกว่าการทำมาก$model->relation->count()หรือcount($model->relation)(เว้นแต่ว่าความสัมพันธ์นั้นได้รับการกระตือรือร้นแล้ว) เนื่องจากมันรันคิวรีการสืบค้นมากกว่าการดึงข้อมูลทั้งหมดสำหรับวัตถุที่เกี่ยวข้องใด ๆ จากฐานข้อมูลเพียงเพื่อนับ เช่นเดียวกันการใช้existsไม่จำเป็นต้องดึงข้อมูลโมเดล

ทั้งสองexists()และcount()การทำงานในทุกประเภทความสัมพันธ์ฉันได้พยายามดังนั้นอย่างน้อยbelongsTo, hasOne, และhasManybelongsToMany


ไม่มีอยู่ในลูเมนไม่แน่ใจว่าทำไม
briankip

@riankip - ควร คุณแน่ใจหรือไม่ว่าคุณได้รับออบเจคความสัมพันธ์ (โดยการเรียกใช้เมธอด) แทนที่จะเป็นคอลเล็กชัน (โดยใช้คุณสมบัติเวทย์มนตร์)?
tremby

18

ฉันชอบที่จะใช้existsวิธีการ:

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

เพื่อตรวจสอบว่ามีโมเดลที่เกี่ยวข้องอยู่หรือไม่ มันทำงานได้ดีบน Laravel 5.2


1
+1; count ($ model-> สัมพันธ์) ได้คืนค่าจริงสำหรับฉันใน Laravel 5.2 แม้ว่าจะไม่มีรายการใดในตารางความสัมพันธ์ -> มีอยู่ () หลอกลวงได้
Ben Wilson

9

หลังจากPhp 7.1คำตอบที่ยอมรับจะใช้ไม่ได้กับความสัมพันธ์ทุกประเภท

เพราะขึ้นอยู่กับประเภทความสัมพันธ์ฝีปากจะกลับCollectionเป็นหรือModel NullและในPhp 7.1 จะโยน count(null)error

ดังนั้นเพื่อตรวจสอบว่าความสัมพันธ์ที่มีอยู่คุณสามารถใช้:

สำหรับความสัมพันธ์เดียว: ตัวอย่างhasOneและbelongsTo

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
Dave Stewart

สิ่งนี้ใช้งานได้ระยะหนึ่ง แต่ก็หยุดทำงานหลังจากที่ฉันอัปเดต Laravel จาก 5.2.29 เป็น 5.2.45 ความคิดใด ๆ ว่าทำไมหรือวิธีการแก้ไขหรือไม่ ตอนนี้มันทำให้ข้อมูลเชิงสัมพันธ์ถูกโหลดด้วยเหตุผลบางอย่าง
Anthony

ฉันได้เพิ่มคำตอบที่มีการแก้ไขสำหรับสิ่งนี้
Anthony

3

คุณสามารถใช้การสัมพันธ์สัมพันธ์วิธีการบนวัตถุรูปแบบ สิ่งนี้ช่วยเบคอนของฉันดังนั้นหวังว่าจะช่วยคนอื่นได้ ฉันได้รับคำแนะนำนี้เมื่อฉันถามคำถามเดียวกันกับ Laracasts


2

ดังที่ 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]);
}

0

ฉันต้อง refactor รหัสของฉันอย่างสมบูรณ์เมื่อฉันอัปเดต PHP เวอร์ชันเป็น 7.2+ เนื่องจากการใช้งานฟังก์ชั่น count ($ x) ไม่ถูกต้อง นี่เป็นความเจ็บปวดที่แท้จริงและน่ากลัวอย่างยิ่งเนื่องจากมีหลายร้อยประเพณีในสถานการณ์ที่แตกต่างกันและไม่มีกฎใดที่เหมาะสมกับทุกสิ่ง ..

กฎที่ฉันปฏิบัติตามเพื่อปรับโครงสร้างทุกอย่างตัวอย่าง:

$ x = Auth :: user () -> posts-> find (6); (ตรวจสอบว่าผู้ใช้มีโพสต์ id = 6 โดยใช้ -> find ())

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

$ x = Auth :: user () -> profile-> แผนก; (ตรวจสอบว่าโปรไฟล์มีบางแผนกหรือไม่สามารถมีได้หลายแผนก)

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

$ x = Auth :: user () -> profile-> get (); (ตรวจสอบว่าผู้ใช้มีโปรไฟล์หลังจากใช้ -> รับ ())

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

ความหวังนี้สามารถช่วยได้แม้กระทั่งคำถามที่ถามไป 5 ปีโพสต์สแต็คโฟลว์นี้ช่วยฉันได้มาก!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.