Zabieramy się za updated count, kontynuacja lekcji poprzednich. Mam nadzieję, że mamy je dobrze przerobione, aby zrozumieć co tu się dzieje. Do dzieła.

Ok, pierwsze co można zrobić to napisać coś takiego:


namespace App\Observers;

use App\Models\Note;

class NoteObserver
{
    /**
     * Handle the Note "created" event.
     */
    public function created(Note $note): void
    {
        //
    }

    /**
     * Handle the Note "updated" event.
     */
    public function updated(Note $note): void
    {
        $note->update_count += 1;
        $note->save();
    }

    /**
     * Handle the Note "deleted" event.
     */
    public function deleted(Note $note): void
    {
        $note->delete_count += 1;
        $note->save();
    }

    /**
     * Handle the Note "restored" event.
     */
    public function restored(Note $note): void
    {
        $note->restore_count += 1;
        $note->save();
    }

    /**
     * Handle the Note "force deleted" event.
     */
    public function forceDeleted(Note $note): void
    {
        //
    }
}

Uwaga – nie próbujmy tego. Opiszę, co się teraz stanie, gdy użyjemy naszych komend (nie licząc tych z fasadą db oraz komendy cichej):

Artisan::command('note-delete-quiet {id}', function (int $id) {

    $ret_val = Note::withoutEvents(function() use($id){

        $note = Note::withoutTrashed()->findOrFail($id);

        $note->delete();
        
        return "deleted quietly";
    });
    $this->comment($ret_val);
    
});

Otóż komendy korzystające z Eloquenta bez trybu cichego będą w pętli nieskończonej. Usunięcie/przywrócenie zostanie potraktowane jako update. Update count się zwiększy, co zostanie potraktowane jako update i tak w pętli aż skończy nam się pamięć.

Będziemy mieli ogromne liczby w update count, ponadto głowy nie daję, że komendy wykonają się poprawnie, ani też nie będziemy musieli z nich wychodzić poprzez ctrl c i jeszcze tymi z fasadą DB rekordy poprawiać.

Jak wyjść z tej pętli? Podpowiedź:

<?php

namespace App\Observers;

use App\Models\Note;

class NoteObserver
{
    /**
     * Handle the Note "created" event.
     */
    public function created(Note $note): void
    {
        //
    }

    /**
     * Handle the Note "updated" event.
     */
    public function updated(Note $note): void
    {
        $note->update_count += 1;
        $note->saveQuietly();
    }

    /**
     * Handle the Note "deleted" event.
     */
    public function deleted(Note $note): void
    {
        $note->delete_count += 1;
        $note->save();
    }

    /**
     * Handle the Note "restored" event.
     */
    public function restored(Note $note): void
    {
        $note->restore_count += 1;
        $note->save();
    }

    /**
     * Handle the Note "force deleted" event.
     */
    public function forceDeleted(Note $note): void
    {
        //
    }
}

Teraz:

  • bierzemy model, który ma wszystkie county na 0
  • usuwamy eloquentem bez trybu cichego
  • przywracamy eloquentem bez trybu cichego
  • delete count to 1
  • restore count to 1
  • update count to 3

Dzieje się tak, ponieważ delete i restore to także update. Natomiast ->saveQuietly() blokuje nieskończoną pętlę.

Możemy chcieć innej logiki, niech delete i restore nie będzie traktowane jak update:

<?php

namespace App\Observers;

use App\Models\Note;

class NoteObserver
{
    /**
     * Handle the Note "created" event.
     */
    public function created(Note $note): void
    {
        //
    }

    /**
     * Handle the Note "updated" event.
     */
    public function updated(Note $note): void
    {
        $note->update_count += 1;
        $note->saveQuietly();
    }

    /**
     * Handle the Note "deleted" event.
     */
    public function deleted(Note $note): void
    {
        $note->delete_count += 1;
        $note->saveQuietly();
    }

    /**
     * Handle the Note "restored" event.
     */
    public function restored(Note $note): void
    {
        $note->restore_count += 1;
        $note->saveQuietly();
    }

    /**
     * Handle the Note "force deleted" event.
     */
    public function forceDeleted(Note $note): void
    {
        //
    }
}

I to by było na tyle. Myślę, że warto będzie poduczyć się z eventów. Na razie jednak wykorzystam sytuację (ogromne liczby updated at w niektórych rekordach) aby zrobić update query w czystym sql.

Ach, przez pomyłkę zepsułem kolumnę updated_at. Naprawmy to, fejkowa baza to aż takie konsekwencje straszne nie są:

UPDATE `notes` 
SET updated_at = CURRENT_TIMESTAMP; 

Przy okazji przypomnieliśmy sobie current_timestamp. Tak, zabawy z SQL potrafią być tragiczne w skutkach, tutaj trzeba stosować skrajnie restrykcyjne BHP. Wystarczyło zmienić update_count na updated_at, aby usunąć wartości ze wszystkich kolumn.

Ok, teraz nasz SQL, niech ustawi update_count na 20 wszystkim rekordom, które mają ten count powyżej 20 000:

UPDATE `notes` 
SET update_count = 20 
WHERE update_count > 20000; 

Przyzwyczajajmy się do SQL, bo będziemy się go uczyć.