Сразу хочу предупредить, что весь материал есть в документациях под тем или иным соусом. Я же постарался скомпоновать всю информацию по событиям в одном месте. Вообще, что такое событие в программировании? И вот что говорит [википедия](http://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D0%B5_(%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)): > Событие это сообщение которое возникает в различных участках исполняемого кода при выполнении определенных условий. Иными словами, программист заранее в своем коде расставляет вызов событий, чтобы в будущем иметь возможность управлять поведением своего приложения в зависимости от ситуации без внедрения в ядро. В базах данных существует такое понятие как триггер. Т.е. некая хранимая процедура вызываемая при наступлении определенных событий. Например, добавление, удаление или обновление записей в таблице. Помимо этого, для одного и того же события может быть создано 2 триггера — до наступления события и после. В Eloquent ORM точно так же. Creating — вызывается до наступления события создания записи. А created – после. Логично предположить, что всего в ORM 10 событий:
Действие Событие до Событие после
Создание Creating Created
Обновление Updating Updated
Сохранение Saving Saved
Удаление Deleting Deleted
Восстановление Restoring Restored
Но не тут то было. Их 11\. Существует еще событие boot, которое вызывается в момент получения объекта. Я бы не назвал это событием — чистой воды ООП. Но раз об этом упомянуто в документации — то стоит затронуть. Идея с boot состоит в том, что мы расширяем базовый метод Eloquent::boot дополняя его своей логикой. Вот пример расширения абстрактной модели Test ```PHP Class Test extends Eloquent { public static function boot() { Log::info('Before boot'); parent::boot(); Log::info('After boot'); } } ``` Теперь давайте рассмотрим как можно использовать события по прямому их назначению: ```PHP // Регистрация триггера с валидацией атрибута name Test::creating(function($test) { Log::info('Before closure'); return is_scalar($test->name) && !empty($test->name); //валидация поля }); // Атрибут валиден Test::create(array( 'name' => 'test' )); // true // Кривой атрибут Test::create(array( 'name' => array('error?') )); //false ``` Идем далее. И посмотрим на ООП стиль событийности для создания/удаления/редактирования записей. Т.е. По аналогии с методом boot прямо в самой модели переопределим методы create, update или delete: ```PHP public static function create(array $attr = array()) { Log::info('Before in model'); $out = (!empty($attr['name']) && is_scalar($attr['name']) ? parent::create($attr) : false; Log::info('After in model'); return $out; } ``` С точки зрения архитектуры проекта, такой подход более понятен на мелком и среднем проекте, т.к. все что относится к модели — находится внутри нее самой. А вот предыдущий способ и все последующие рекомендуется выносить, например, в файл **/app/events.php** по аналогии с /app/filters.php, который подключается при старте laravel. Т.е. из файла **/app/start/global.php**. Итак, следующий способ зарегистрировать триггер — при помощи модели наблюдения. А вот регистрировать данный наблюдатель можно как динамически в зависимости от условий, так и статично при помощи метода boot: ```PHP Class Test extends Eloquent { public static function boot() { self::observe(new TestObserver); parent::boot(); } } class TestObserver { public function creating($test) { Log::info('Before observer create'); } public function created($test) { Log::info('After observer create'); } } ``` При всем при этом, никто не запрещает совмещать способы создания триггеров. Т.е. фактически, мы уже знаем 3 разных способа задания события для before create, after create. Точно так же и для update, delete. Ну и остался последний, четвертый способ наблюдения за событиями модели. Последний и самый мощный на мой взгляд — Event::listen: ```PHP Event::listen('eloquent.creating: Test', function($obj)){ Log::info($obj); }); ``` Почему мощный? Потому, что этот способ позволяет слушать не только конкретное событие, конкретной модели. Мы можем слушать сразу все события eloquent. Можем слушать все события конкретной модели. И поможет нам в этом козырная звездочка. Заменяем ей нужную часть имени события и воля... ```PHP Event::listen('eloquent.*', function($obj)){ Log::info($obj); }); ``` Вторая, самая важная особенность фасада Event в том, что он позволяет создавать произвольные события. Допустим, регистрация нового пользователя. Авторизация в админке и т.д. и т.п. Делается это очень просто при помощи метод fire: ```PHP Event::fire('user.reg', $user); ``` Ну а слушать через Event::listen мы уже умеем. Помимо регистрации произвольных событий, Event фасад умеет еще и помещать триггер в очередь на случай если необходимо выполнить какую-то длительную и ресурсоемкую операцию. ```PHP Event::queue('user.reg', , function()){ }); ``` Ну и наконец Event поддерживает подписчиков. Так называемые классы, которые позволяют навешать сразу несколько триггеров на одно событие. ```PHP Event::subscribe(new UserEventHandler); ``` Это может быть удобно тогда, хочется скомпоновать логически связанные между собой триггеры. Допустим, пользовательские триггеры (_авторизация, логаут, редактирование профиля_). Триггеры базы данных (_создание, обновлении, удаление_) и т. д. С событиями на этом все. Но перехват ошибок своего рода тоже события. Поэтому хочу хотя бы кратко и об этом рассказать. На самом деле, тут все просто: ```PHP App::error(function(Exception $e){ //действие }); ``` Но не на одном перехватчике проекты строятся. Ведь в проектах может быть много исключений. Начиная с некорректного SQL-запроса и заканчивая отсутствием прав доступа. Соответственно логично отдавать для разных исключений разные ошибки. И тут на помощь приходит [контроль типов](http://www.php.net/manual/ru/language.oop5.typehinting.php). Вообще, регистрация ошибок происходит в файле app/start/global.php, если таковых много, то желательно вынести в отдельный файл как и события - допустим в app/errors.php. Помимо метода error есть еще down – синоним для события illuminate.app.down. Говорящее название — при завершении работы. Если сделать поиск по методу listen в папке vendor/laravel/framework, то можно найти упоминания о таких событиях, как: * artisan.start * illuminate.queue.failed * illuminate.log * illuminate.app.down * illuminate.query * router.matched * router.{filter} * router.filter: {filter} * auth.attempt Ну и раз уж затронули консольную команду artisan, то грех не затронуть события composer-а. Ведь Laravel ставится, обновляется и устанавливает компоненты именно через него. Поэтому composer можно считать по праву частью laravel. Для тех, кто не обращал внимание, composer поддерживает целых аж 18 событий до начала или после установки, обновления или удаления пакета или самого проекта. Данные события указываются в секции scripts файла composer.json. И после установки laravel там автоматически регистрируются 3 события разобрать которые я вам всем предлагаю уже самостоятельно...