Laravel Eloquent Update nur, wenn Änderungen vorgenommen wurden


85

Gibt es eine Möglichkeit, einen Datensatz in Laravel mithilfe beredter Modelle zu aktualisieren, wenn eine Änderung an diesem Datensatz vorgenommen wurde? Ich möchte nicht, dass ein Benutzer die Datenbank ohne guten Grund immer wieder anfordert und nur auf die Schaltfläche drückt, um Änderungen zu speichern. Ich habe eine javascriptFunktion, die die Schaltfläche zum Speichern aktiviert und deaktiviert, je nachdem, ob sich etwas auf der Seite geändert hat, aber ich möchte wissen, ob es möglich ist, diese Art von Funktion auch auf der Serverseite auszuführen. Ich weiß, dass ich es selbst schaffen kann (dh ohne auf eine interne Funktionalität des Frameworks einzugehen), indem ich nur überprüfe, ob sich der Datensatz geändert hat, aber bevor ich es auf diese Weise mache, möchte ich wissen, ob sich das beredte Laravel-Modell bereits darum kümmert das, also muss ich das Rad nicht neu erfinden.

So aktualisiere ich einen Datensatz:

$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
Aktivieren Sie die Datenbankprotokollierung und überprüfen Sie die Protokolle, um festzustellen, welche Abfrage Eloquent beim Speichern tatsächlich ausführt: Sie könnten angenehm überrascht sein
Mark Baker

4
Beachten Sie, dass Laravel-Modelle ein dirtyFlag enthalten, mit dem bestimmt wird, ob tatsächlich eine Aktualisierung der Datenbank erforderlich ist. Dieses Flag wird gesetzt, indem die ursprünglichen findSpaltenwerte mit den Werten an dem Punkt verglichen werden, an dem Sie das Speichern ausführen
Mark Baker

@ MarkBaker Das ist ein toller Tipp!
user2755140

Antworten:


175

Du machst es schon!

save()prüft, ob sich etwas im Modell geändert hat. Wenn dies nicht der Fall ist, wird keine Datenbankabfrage ausgeführt.

Hier ist der relevante Teil des Codes in Illuminate\Database\Eloquent\Model@performUpdate:

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

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

    return true;
}

Die getDirty()Methode vergleicht einfach die aktuellen Attribute mit einer Kopie, die beim originalErstellen des Modells gespeichert wurde . Dies geschieht in der syncOriginal()Methode:

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

    $this->syncOriginal();

    $this->fill($attributes);
}

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

    return $this;
}

Wenn Sie überprüfen möchten, ob das Modell verschmutzt ist, rufen Sie einfach an isDirty():

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

Oder wenn Sie ein bestimmtes Attribut überprüfen möchten:

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

Das ist großartig. Vielen Dank. Ich frage mich jetzt, wie ich auf diese schmutzige Flagge zugreifen kann, um zu erfahren, ob ein Aktualisierungsversuch durchgeführt wurde, ohne Änderungen vorzunehmen. Ich meine: die Rückkehr für diese Aktion?
user2755140

1
@DaseinA Dafür kannst du verwenden isDirty(). Siehe die aktualisierte Antwort
lukasgeiter

2
Lesen Sie diese Antwort unbedingt durch, bevor Sie sie verwenden isDirty().
Alex

1
Es gibt eine getChanges()Methode. Überprüfen Sie meine Antwort stackoverflow.com/a/54132163/1090395
Mladen Janjetovic

Zu Ihrer Information isDirty()wird es sein, truewenn Sie Ihre Attribute nicht richtig umsetzen . Ich hatte einen Float, der genau der gleiche war wie in der Datenbank. Da ich den Float jedoch mit einer Zeichenfolge (Beispiel "10.50" anstelle von 10.50) festlegte, wurde er als Änderung erkannt und eine Aktualisierung durchgeführt.
Maarten de Graaf


11

Ich möchte diese Methode hinzufügen. Wenn Sie ein Bearbeitungsformular verwenden, können Sie diesen Code verwenden, um die Änderungen in Ihrer update(Request $request, $id)Funktion zu speichern :

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

Beachten Sie, dass Sie Ihre Eingaben mit demselben Spaltennamen benennen müssen. Die fill()Funktion erledigt die ganze Arbeit für Sie :)


3
Dies ist eigentlich die Antwort, nach der ich gesucht habe. Ich habe den Namen vergessen fillund erfahren, wie ich eine Massenanforderung an ihn weiterleiten kann. Vielen Dank! Ich musste die ID allerdings nicht weitergeben, da ich sie aktualisiere, also ist sie bereits da $request->id.
Blamb
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.