Laravel Eloquent อัปเดตหากมีการเปลี่ยนแปลง


87

มีวิธีใดบ้างในการอัปเดตบันทึกใน Laravel โดยใช้แบบจำลองที่มีฝีปากหากมีการเปลี่ยนแปลงบันทึกนั้น ฉันไม่ต้องการให้ผู้ใช้ใด ๆ ขอฐานข้อมูลโดยไม่มีเหตุผลที่ดีซ้ำแล้วซ้ำเล่าเพียงแค่กดปุ่มเพื่อบันทึกการเปลี่ยนแปลง ฉันมีjavascriptฟังก์ชั่นที่เปิดใช้งานและปิดใช้งานปุ่มบันทึกตามว่ามีอะไรเปลี่ยนแปลงในหน้าหรือไม่ แต่ฉันต้องการทราบว่าเป็นไปได้หรือไม่ที่จะใช้คุณลักษณะนี้ในฝั่งเซิร์ฟเวอร์ด้วย ฉันรู้ว่าฉันสามารถทำได้ด้วยตัวเอง (หมายถึง: โดยไม่สนใจฟังก์ชันภายในของเฟรมเวิร์ก) เพียงแค่ตรวจสอบว่าบันทึกมีการเปลี่ยนแปลงหรือไม่ แต่ก่อนที่จะทำเช่นนั้นฉันต้องการทราบว่าโมเดลที่มีฝีปากของ Laravel ดูแลอยู่แล้ว ดังนั้นฉันไม่จำเป็นต้องประดิษฐ์ล้อขึ้นมาใหม่

นี่คือวิธีที่ฉันใช้ในการอัปเดตบันทึก:

$product = Product::find($data["id"]);
$product->title = $data["title"];
$product->description = $data["description"];
$product->price = $data["price"];
//etc (string values were previously sanitized for xss attacks)
$product->save();

3
ทำไมไม่เปิดใช้งานการบันทึกฐานข้อมูลแล้วตรวจสอบบันทึกเพื่อดูว่าข้อความค้นหาใดที่ Eloquent ดำเนินการจริงเมื่อคุณทำการบันทึก: คุณอาจประหลาดใจอย่างมาก
Mark Baker

4
โปรดสังเกตว่าโมเดล Laravel ถือdirtyแฟล็กที่ใช้เพื่อพิจารณาว่าจำเป็นต้องมีการอัพเดตบนฐานข้อมูลจริงหรือไม่และแฟล็กนี้ถูกตั้งค่าโดยการเปรียบเทียบfindค่าคอลัมน์ดั้งเดิมกับค่า ณ จุดที่คุณดำเนินการบันทึก
Mark Baker

@MarkBaker นั่นเป็นเคล็ดลับที่ยอดเยี่ยม!
user2755140

คำตอบ:


180

คุณทำได้แล้ว!

save()จะตรวจสอบว่ามีการเปลี่ยนแปลงบางอย่างในโมเดลหรือไม่ หากยังไม่มีจะไม่เรียกใช้แบบสอบถามฐานข้อมูล

นี่คือส่วนที่เกี่ยวข้องของโค้ดในIlluminate\Database\Eloquent\Model@performUpdate:

protected function performUpdate(Builder $query, array $options = [])
{
    $dirty = $this->getDirty();

    if (count($dirty) > 0)
    {
        // runs update query
    }

    return true;
}

getDirty()วิธีการเพียงแค่เปรียบเทียบคุณลักษณะปัจจุบันพร้อมสำเนาบันทึกไว้ในoriginalเมื่อรูปแบบจะถูกสร้างขึ้น สิ่งนี้ทำได้ในsyncOriginal()วิธีการ:

public function __construct(array $attributes = array())
{
    $this->bootIfNotBooted();

    $this->syncOriginal();

    $this->fill($attributes);
}

public function syncOriginal()
{
    $this->original = $this->attributes;

    return $this;
}

หากคุณต้องการตรวจสอบว่ารุ่นสกปรกเพียงโทรisDirty():

if($product->isDirty()){
    // changes have been made
}

หรือหากคุณต้องการตรวจสอบคุณสมบัติบางอย่าง:

if($product->isDirty('price')){
    // price has changed
}

เยี่ยมมาก ขอขอบคุณ. ฉันสงสัยว่าตอนนี้ฉันจะเข้าถึงแฟล็กสกปรกนั้นได้อย่างไรเพื่อทราบว่ามีการพยายามอัปเดตโดยไม่ทำการเปลี่ยนแปลงใด ๆ หรือไม่? ฉันหมายถึงการกลับมาของการกระทำนั้น?
user2755140

1
@DaseinA คุณสามารถใช้isDirty()สำหรับสิ่งนั้น ดูคำตอบที่อัปเดต
lukasgeiter

2
ให้กับผู้ที่อ่านข้อความนี้ให้แน่ใจว่าได้ตรวจสอบคำตอบนี้isDirty()ก่อนที่จะใช้
Alex

1
มีgetChanges()วิธีการ ตรวจสอบคำตอบของฉันstackoverflow.com/a/54132163/1090395
Mladen Janjetovic

FYI isDirty()จะเป็นtrueเช่นนั้นหากคุณไม่ได้ระบุคุณสมบัติของคุณให้ถูกต้อง ฉันมี float ที่เหมือนกับในฐานข้อมูล แต่เนื่องจากฉันตั้งค่า float ด้วยสตริง (เช่น "10.50" แทนที่จะเป็น 10.50) มันจะตรวจพบว่าเป็นการเปลี่ยนแปลงและทำการอัปเดต
Maarten de Graaf


11

ฉันต้องการเพิ่มวิธีนี้หากคุณใช้แบบฟอร์มแก้ไขคุณสามารถใช้รหัสนี้เพื่อบันทึกการเปลี่ยนแปลงในupdate(Request $request, $id)ฟังก์ชันของคุณ:

$post = Post::find($id);    
$post->fill($request->input())->save();

โปรดทราบว่าคุณต้องตั้งชื่ออินพุตของคุณด้วยชื่อคอลัมน์เดียวกัน fill()ฟังก์ชั่นจะทำทุกอย่างสำหรับคุณ :)


3
นี่คือคำตอบที่ฉันกำลังค้นหาฉันลืมชื่อfillและวิธีส่งคำขอจำนวนมากไป ขอบคุณ! ผมไม่จำเป็นต้องผ่าน ID แม้ว่าตั้งแต่ im $request->idปรับปรุงเพื่อให้มันมีอยู่แล้ว
ตำหนิ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.