라라벨 엘로퀀트 모델 이벤트 고찰 share

today 2017-10-22 face Posted by appkr turned_in Work & Play forum 0

라라벨 엘로퀀트에서 발생하는 모델 이벤트를 실험한 결과 입니다. 선점 잠금과 비선점 잠금 실험을 위한 프로젝트에 이벤트 리스너를 등록하고 엘로퀀트 모델을 DB에 저장하고, 변경한 후 DB에 저장하고, 삭제할 때 어떤 이벤트가 발생하는지 살펴 봤습니다.

이벤트를 잡기 위한 리스너 클로저는 아래와 같습니다.

<?php // https://github.com/appkr/db-lock-poc/blob/master/app/Providers/EventServiceProvider.php

class EventServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Event::listen('eloquent.*', function ($event) {
            Log::info($event);
        });
    }
}

관찰자(Observer) 패턴은 관찰의 대상이 되는 타입에, 대상을 관찰하려는 타입을 등록해두고, 특정 사건(Event)이 발생하면 등록된 관찰자의 함수를 호출하는 겁니다. 쉽게 말하면, “밥 다되면 불러줘~”라고 미리 말해두고, 밥이 다 되면 알려주는 거죠.

“관찰자를 등록하고 사건이 발생하면 등록된 관찰자들에게 알려준다”는 큰 개념은 같지만, 라라벨의 엘로퀀트 모델은 $observables 변수에 객체가 아닌 문자열로 관찰자를 등록합니다. 그리고 엘로퀀트에서는 save()와 같은 퍼블릭 함수가 작동할 때, 자신의 fireModelEvent('created') 함수를 호출하고, 이 함수가 다시 관찰자에서 이벤트와 같은 이름을 가진 함수, 예를 들어 created($this)를 호출하는 식으로 작동합니다.

• • •

1. Insert

$model->update(), $model->push(), $model->touch() 등의 API도 결국에는 save() 함수를 거치게 됩니다. save() 함수는 saving 이벤트를 던진 후, 다시 Insert를 해야할지 Update를 해야할지 판단하고, performInsert() 또는 performUpdate() 함수를 선택적으로 호출합니다. 분기된 함수 안에서 다시 creating, created, .. 등의 이벤트를 던집니다. 분기된 함수 오퍼레이션이 끝나면 save() 함수는 saved 이벤트를 던지고 수명을 다합니다.

따라서, saving -> creating -> created -> saved 순서로 이벤트가 발생합니다.

# https://github.com/appkr/db-lock-poc/blob/master/app/Http/Controllers/ProductController.php#L42

[...] local.INFO: eloquent.booting: Myshop\Domain\Model\User
[...] local.INFO: eloquent.booted: Myshop\Domain\Model\User
[...] local.INFO: select * from `users` where `email` = ? limit 1 ["admin@foo.com"]
[...] local.INFO: eloquent.booting: Myshop\Domain\Model\Product
[...] local.INFO: eloquent.booted: Myshop\Domain\Model\Product
[...] local.INFO: eloquent.saving: Myshop\Domain\Model\Product
[...] local.INFO: eloquent.creating: Myshop\Domain\Model\Product
[...] local.INFO: insert into `products` (`title`, `stock`, `price`, `description`, `updated_at`, `created_at`) values (?, ?, ?, ?, ?, ?) ["TEST TITLE",10,1000,"TEST DESCRIPTION","2017-10-22 10:21:53","2017-10-22 10:21:53"]
[...] local.INFO: eloquent.created: Myshop\Domain\Model\Product
[...] local.INFO: eloquent.saved: Myshop\Domain\Model\Product
[...] local.INFO: select * from `products` where `id` = ? limit 1 [12]
[...] local.INFO: eloquent.booting: Myshop\Domain\Model\Review
[...] local.INFO: eloquent.booted: Myshop\Domain\Model\Review
[...] local.INFO: select * from `reviews` where `reviews`.`product_id` in (?) and `reviews`.`deleted_at` is null [12]

2. Update

saving -> updating -> updated -> saved 순.

# https://github.com/appkr/db-lock-poc/blob/master/app/Http/Controllers/ProductController.php#L59

[...] local.INFO: eloquent.booting: Myshop\Domain\Model\User
[...] local.INFO: eloquent.booted: Myshop\Domain\Model\User
[...] local.INFO: select * from `users` where `email` = ? limit 1 ["admin@foo.com"]
[...] local.INFO: eloquent.booting: Myshop\Domain\Model\Product
[...] local.INFO: eloquent.booted: Myshop\Domain\Model\Product
[...] local.INFO: select * from `products` where `products`.`id` = ? and `products`.`deleted_at` is null limit 1 for update [12]
[...] local.INFO: eloquent.booting: Myshop\Domain\Model\Review
[...] local.INFO: eloquent.booted: Myshop\Domain\Model\Review
[...] local.INFO: select * from `reviews` where `reviews`.`product_id` in (?) and `reviews`.`deleted_at` is null [12]
[...] local.INFO: select * from `products` where `id` = ? limit 1 [12]
[...] local.INFO: select * from `reviews` where `reviews`.`product_id` in (?) and `reviews`.`deleted_at` is null [12]
[...] local.INFO: eloquent.saving: Myshop\Domain\Model\Product
[...] local.INFO: eloquent.updating: Myshop\Domain\Model\Product
[...] local.INFO: update `products` set `title` = ?, `description` = ?, `version` = ?, `updated_at` = ? where `id` = ? ["새 상품 (상품명 수정됨)","...",2,"...",12]
[...] local.INFO: eloquent.updated: Myshop\Domain\Model\Product
[...] local.INFO: eloquent.saved: Myshop\Domain\Model\Product
[...] local.INFO: select * from `products` where `id` = ? limit 1 [12]
[...] local.INFO: select * from `reviews` where `reviews`.`product_id` in (?) and `reviews`.`deleted_at` is null [12]

3. Delete

deleting -> deleted 순.

# https://github.com/appkr/db-lock-poc/blob/master/app/Http/Controllers/ProductController.php#L96

[...] local.INFO: eloquent.booting: Myshop\Domain\Model\Product
[...] local.INFO: eloquent.booted: Myshop\Domain\Model\Product
[...] local.INFO: select * from `products` where `id` = ? and `products`.`deleted_at` is null limit 1 ["12"]
[...] local.INFO: eloquent.booting: Myshop\Domain\Model\Review
[...] local.INFO: eloquent.booted: Myshop\Domain\Model\Review
[...] local.INFO: select * from `reviews` where `reviews`.`product_id` in (?) and `reviews`.`deleted_at` is null [12]
[...] local.INFO: eloquent.booting: Myshop\Domain\Model\User
[...] local.INFO: eloquent.booted: Myshop\Domain\Model\User
[...] local.INFO: select * from `users` where `email` = ? limit 1 ["admin@foo.com"]
[...] local.INFO: select * from `reviews` where 0 = 1 and `reviews`.`deleted_at` is null
[...] local.INFO: eloquent.deleting: Myshop\Domain\Model\Product
[...] local.INFO: update `products` set `deleted_at` = ?, `updated_at` = ? where `id` = ? ["...","...",12]
[...] local.INFO: eloquent.deleted: Myshop\Domain\Model\Product
comments powered by Disqus
keyboard_arrow_up