• Время чтения ~1 мин
  • 25.11.2023

Если у вас есть события Наблюдателя для обновления или удаления записей, важно знать, что они выполняются только при обновлении отдельных записей, а не при массовом обновлении или удалении.

Код Наблюдателя:

app/Observers/PostObserver.php:

class PostObserver{    public function deleted(Post $post)    {        // Например, удаляет связанные файлы изображений    }}

Этот Наблюдатель зарегистрирован в Service Provider:

app/Providers/AppServiceProvider.php:

use App\Models\Post;use App\Observers\PostObserver;class AppServiceProvider extends ServiceProvider{    public function boot()    {        Post::observe(PostObserver::class);    }}

А теперь представьте три разных Eloquent запроса:

$post = Post::first();$post->delete();// Это БУДЕТ запускать НаблюдателяPost::find(2)->delete();// Это также БУДЕТ запускать НаблюдателяPost::where('id', '>', 3)->delete();// Но это НЕ БУДЕТ запускать Наблюдателя!$user->posts()->delete();// Это также НЕ БУДЕТ запускать Наблюдателя!

Причина в том, что события Наблюдателя происходят из Eloquent Модели. В случае delete() из Query Builder запрос выполняется непосредственно к базе данных, минуя отдельную модель и её события.

Даже если результатом запроса является одна единственная модель Eloquent, Наблюдатели не будут запущены.

Post::where('id', 4)->delete();

Это верно для любого метода Наблюдателя: updated() или updating(), delete() или deleting().

Это так же важно в случае некоторых пакетов, которые автоматически регистрируют Наблюдателей.

Например, в случае Spatie Media Library она регистрирует метод deleted(), который не удалит связанный медиа файлы, если массово удалить записи Модели, а не одну Модель.

laravel-medialibrary/src/InteractsWithMedia.php:

trait InteractsWithMedia{    public static function bootInteractsWithMedia()    {        static::deleting(function (HasMedia $model) {            if ($model->shouldDeletePreservingMedia()) {                return;            }            if (in_array(SoftDeletes::class, class_uses_recursive($model))) {                if (! $model->forceDeleting) {                    return;                }            }            $model->media()->cursor()->each(fn (Media $media) => $media->delete());        });    }

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Об авторе CrazyBoy49z
WORK EXPERIENCE
Контакты
Ukraine, Lutsk
+380979856297