{{TOC}} У всех нас рано или поздно наступает момент в жизни, когда мы хотим поделиться кучей уведомлений с пользователем. На первый взгляд это может вызвать некоторые сложности, но у меня имеется шаблон, который может решить проблему "в лоб". //Я хочу выразить отдельную благодарность ((http://fideloper.com/ Крису Фидао)) за оказанную мне помощь в корректировке и улучшении этой статьи. Если вас интересует больше информации о прагматичном проектировании Laravel-приложений, советую прочитать ((https://leanpub.com/implementinglaravel его книгу)).// **Примечание: Вы должны быть относительно знакомы с Illuminate / ((док4:eloquent Eloquent)) и различными типами отношений, а также иметь некоторый опыт наследования.** == Цель == Цель состоит в том, чтобы при входе пользователя в личный аккаунт, показывать ему все уведомления. Кроме того, здесь могут существовать различные типы уведомлений. Например, может быть уведомление о новом сообщении, и уведомление о событии. Они могут иметь различные форматы. == План атаки == Для "атаки" мне нужен простой вызов чего-то типа: %%Notification::allForUser($userId)%%, вместо того, чтобы использовать какие-то сумасшедшие запросы каждый раз, когда я создаю новый тип уведомления. Кроме того, уведомления должны быть очень похожи: мы не хотим, чтобы уведомления, подтверждаемые пользователем, кардинально отличались от наших уведомлений писем. Для этого задания мы возьмем два типа уведомлений, использующихся на FaceBook: письма и сообщения. Мы сделаем следующее: 1. Создадим базовую Eloquent-модель уведомлений, которую мы будем использовать для всех будущих типов уведомлений. 2. Реализуем некоторый образец модели уведомлений для писем и сообщений. 3. Используем ((док4:responses#составител+и))ь шаблонов для того, чтобы добавить уведомление для каждого интерфейса. == Простой способ получения уведомлений == Чтобы выбрать наиболее простой метод получения всех уведомлений для пользователя, мы могли бы пойти немного дальше и создать репозиторий. Но это может вызвать некоторые проблемы, когда мы создаем новое уведомление для игр или какое-либо уведомление, выходящее за рамки данной реализации. С другой стороны, мы сохраним всю информацию о наших уведомлениях в ((ВП:JSON))-формате или в сериализованном формате в нашей базе данных, но с этим немного неудобно работать в дальнейшем и простой класс уведомления должен будет знать обо всех типах уведомлений, которые будут использоваться в нашем приложении. Вместо этого, давайте воспользуемся отношением Eloquent //MorphToOne// и создадим родительскую модель уведомлений, которая относится к уведомлениям нашего пользователя. Тогда мы сможем использовать магические методы, чтобы пройти все взаимодействия наших дочерних уведомлений. %% class Notification extends Eloquent { public function notification() { return $this->morphTo(); } public function user() { return $this->belongsTo('User'); } public function __get($key) { // Перед передачей значения дальше по цепочке, мы должны // проверить, существует ли допустимое значение return parent::__get($key) ?: $this->notification->__get($key); } } %% == Стандартизованный договор == Когда я размышлял над уведомлениями для моего пользовательского интерфейса, я подумал, что мне больше нравится интерфейс с описанием, кнопкой подтверждения и кнопкой отмены. Я не хочу, чтобы мой интерфейс производил очень много действий, поэтому я иду дальше и создаю маленький абстрактный класс, чтобы убедиться, что я следую договору, позволяющему легко расширять функционал. Здесь же мы объявляем родительскую модель уведомлений. %% namespace Notifications; abstract class NotifiableModel extends \Eloquent { // Вернет сообщение, которое мы хотим // показать в нашем уведомлении abstract public function getMessageAttribute(); // Вернет ссылку на маршрут, которая // обрабатывает успешный ответ на уведомление abstract public function getAcceptLinkAttribute(); // Вернет ссылку на маршрут, которая // обрабатывает отрицательный ответ на уведомление abstract public function getDeclineLinkAttribute(); // Дает нам возможность ссылаться на // родительскую модель уведомлений public function notification() { return $this->morphOne('Notification'); } } %% == Наши классы уведомлений == Давайте разберем наш %%PostNotification%%. Например, я хочу сказать "Джош написал что-то на вашей стене", значит должна быть ссылка на сообщение, которое нас извещает об этом. %%MessageNotification%% очень похож на него, за исключением нескольких изменений, относящихся к письмам, а не к сообщениям. %% namespace Notifications; class PostNotification extends NotifiableModel { // Я выбираю префикс к таблицам уведомлений // чтобы имитировать ресурсы, на которые они указывают. protected $table = 'notifications_posts'; public function getMessageAttribute() { // Предположим, что наше письмо возвращает // нам имя пользователя $username = $this->post->sender->name; return "{$username} оставил письмо на вашей стене"; } public function getAcceptLinkAttribute() { // Этот маршрут обрабатывает удаление // уведомления и переадресует нас на страницу с сообщением $route = 'notifications.posts.accept'; $title = 'Панель сообщения'; $parameters = array( $this->getAttribute('id') ); return link_to_route($route, $title, $parameters); } public function getDeclineLinkAttribute() { // Этот маршрут обрабатывает удаление // уведомления и переводит нас обратно // на страницу, где мы находились ранее $route = 'notifications.posts.decline'; $title = 'Отменить'; $parameters = array( $this->getAttribute('id') ); return link_to_route($route, $title, $parameters); } // Связь с сообщением для уведомления public function post() { return $this->belongsTo('Письмо'); } } %% == Наша схема базы данных == Хоть это и простой набросок шаблона, показывающий, как обрабатывать уведомления, я хотел бы остановиться на том, как будет выглядеть схема для базы данных для этого примера: %%(t) notifications id - integer notification_id - integer notification_type - string timestamps notifications_posts id - integer post_id - integer timestamps notifications_messages id - integer message_id - integer timestamps %% == Наш интерфейс администратора == Итак, мы хотим, чтобы наши уведомления были доступны для всех наших шаблонов, включающих шаблон %%(t)notificationCenter%%. Поэтому мы используем ((http://laravel.com/docs/responses#view-composers составитель шаблонов)), чтобы быть уверенными, что мы никогда не забудем отправить уведомление в пользовательский интерфейс. %% View::composer('notificationCenter', function($view) { $user = Auth::user(); $notifications = Notification::where('user_id', $user->id)->get(); $view->with('notifications', $notifications); }); %% Теперь часть нашего шаблона %%(t)notificationCenter%% выглядит следующим образом: %% %% == Что за работу мы проделали? == В этой статье мы затронули множество тем, но есть еще и не описанный материал. Мы рассмотрели принцип создания шаблона, работающего над обработкой уведомлений в панели администратора. 1. Мы создали родительскую модель уведомлений, которая позволяет разбирать все наши различные типы уведомлений из одного места. 2. Мы создали договор для наших типов уведомлений, используя абстрактный класс, который именуется %%NotifiableModel%%. 3. Мы создали реализацию %%PostNotification%%. 4. Наконец, мы использовали составитель шаблонов, чтобы сделать наш шаблон %%(t)notificationCenter%% намного проще, всегда используя выборку из уведомлений авторизованного пользователя. Мы не рассмотрели создание наших уведомлений и их прикрепление к родительскому контейнеру уведомлений, но это похоже на отношение ((док4:eloquent#полиморфические Polymorphic-One-To-One)). Мы также не рассмотрели реализацию %%(t)notifications.posts.accept%% и %%(t)notifications.posts.decline%% маршрутов, хотя это уже специфика приложения. В нашем примере с письмом, %%(t)accept%% маршрут удалит уведомление и перенаправит нас на страницу с сообщением, в то время как %%decline%% маршрут просто удалит уведомление.