Laravel Eloquent si aggiorna solo se sono state apportate modifiche


87

C'è un modo per aggiornare un record in Laravel utilizzando modelli eloquenti solo se è stata apportata una modifica a quel record? Non voglio che nessun utente richieda il database senza una buona ragione più e più volte, basta premere il pulsante per salvare le modifiche. Ho una javascriptfunzione che abilita e disabilita il pulsante di salvataggio a seconda che qualcosa sia cambiato nella pagina, ma vorrei sapere se è possibile assicurarmi di fare questo tipo di funzionalità anche sul lato server. So di poterlo fare da solo (ovvero: senza fare appello a una funzionalità interna del framework) semplicemente controllando se il record è cambiato, ma prima di farlo in questo modo, vorrei sapere se il modello eloquente di Laravel si occupa già di quello, quindi non ho bisogno di reinventare la ruota.

Questo è il modo in cui uso per aggiornare un record:

$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
Perché non abilitare la registrazione del database e quindi controllare i log per vedere quale query Eloquent esegue effettivamente quando si esegue un salvataggio: potresti essere piacevolmente sorpreso
Mark Baker

4
Si noti che i modelli Laravel contengono un dirtyflag che viene utilizzato per determinare se un aggiornamento sul database è effettivamente richiesto, e questo flag viene impostato confrontando i findvalori della colonna originale con i valori nel punto in cui si esegue il salvataggio
Mark Baker

@MarkBaker Questo è un ottimo consiglio!
user2755140

Risposte:


180

Lo stai già facendo!

save()controllerà se qualcosa nel modello è cambiato. In caso contrario, non verrà eseguita una query db.

Ecco la parte rilevante del codice 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;
}

Il getDirty()metodo confronta semplicemente gli attributi correnti con una copia salvata originalquando viene creato il modello. Questo viene fatto nel syncOriginal()metodo:

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

    $this->syncOriginal();

    $this->fill($attributes);
}

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

    return $this;
}

Se vuoi controllare se il modello è sporco chiama isDirty():

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

O se vuoi controllare un determinato attributo:

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

È fantastico. Grazie. Mi chiedo ora come posso accedere a quel flag sporco per sapere se è stato effettuato un tentativo di aggiornamento senza apportare alcuna modifica? Voglio dire: il ritorno per quell'azione?
user2755140

1
@DaseinA Puoi usare isDirty()per quello. Vedi la risposta aggiornata
lukasgeiter

2
Per coloro che leggono questo, assicurati di controllare questa risposta prima dell'uso isDirty().
Alex

1
C'è un getChanges()metodo. Controlla la mia risposta stackoverflow.com/a/54132163/1090395
Mladen Janjetovic

Cordiali saluti isDirty(), truese non interpreti correttamente i tuoi attributi. Avevo un float che era esattamente lo stesso del database, tuttavia poiché stavo impostando il float con una stringa (esempio "10.50" invece di 10.50) lo rileverebbe come una modifica ed eseguirà un aggiornamento.
Maarten de Graaf


11

Mi piace aggiungere questo metodo, se stai usando un modulo di modifica, puoi usare questo codice per salvare le modifiche nella tua update(Request $request, $id)funzione:

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

tieni presente che devi nominare i tuoi input con lo stesso nome di colonna. La fill()funzione farà tutto il lavoro per te :)


3
Questa è in realtà la risposta che stavo cercando, ho dimenticato il nome fille come passare la richiesta di massa. Grazie! Non ho avuto bisogno di passare l'ID, dato che sto aggiornando, quindi è già lì $request->id.
blamb
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.