Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)

Этот учебник является частью серии статей Пишем свой стартап на PHP на Envato Tuts +. В этой серии я направляю вас через запуск приложения от концепции до готового продукта, используя приложение Планировщик встреч в качестве реального приложения. На каждом шаге я делаю релиз кода планировщика собраний в качестве примеров с открытым исходным кодом, из которых вы можете узнать что-то новое. Я также рассмотрю связанные с запуском бизнес-вопросы по мере их возникновения.
В предыдущем эпизоде я описал создание инфраструктуры для отслеживания изменений на собраниях, чтобы мы знали, как мы будем делиться обновлениями с участниками. В этом эпизоде я расскажу о мониторинге логов и доставке уведомлений об изменениях по электронной почте.
Если вы еще не опробовали Планировщик собраний, запланируйте свою первую встречу. Как только вам ответят ваши коллеги и друзья, вы увидите уведомления в действии. Я участвую в комментариях ниже, поэтому, пожалуйста, поделитесь своими отзывами. Меня особенно интересует, если вы хотите предложить новые функции или темы для будущих учебников.
Напомним, что весь код Планировщика собраний написан на Yii2 Framework для PHP. Если вы хотите узнать больше о Yii2, ознакомьтесь с нашей параллельной серией Программирование с Yii2.
Мониторинг обновлений собрания
С MeetingLog из предыдущего эпизода мы будем регулярно отслеживать, когда изменения будут составлять несколько минут, чтобы затем объединить их в одно обновление для другого участника (участников) или организатора собрания.
Наш DaemonController в экшене actionFrequent будет проверять собрания со свежими обновлениями каждые несколько минут:
public function actionFrequent() { // called every three to five minutes // notify users about fresh changes Meeting::findFresh();
Выбор правильных людей для уведомления
Meeting::findFresh()
просматривает журнал для записей, которые старше, чем MeetingLog::TIMELAPSE
, в настоящее время - это пять минут. Когда он находит их, он смотрит на каждого из участников, участвующих в внесении изменений, и уведомляет их через Meeting::notify()
:
public static function findFresh() { // identify all meetings with log entries not yet cleared $meetings = Meeting::find()->where('logged_at-cleared_at>0')->all(); foreach ($meetings as $m) { // to do - choose a different safe gap, for now an hour if ((time()-$m->logged_at)>3600) { // to do - consider clearing out these old ones continue; } // uncleared log entry older than TIMELAPSE if ((time()-$m->logged_at) > MeetingLog::TIMELAPSE) { // $logs = MeetingLog::find()->where(['meeting_id'=>$m->id])->groupBy('actor_id')->all(); $current_actor=0; foreach ($logs as $log) { if ($log->actor_id<>$current_actor) { $current_actor = $log->actor_id; // new actor, let's notify others if ($log->actor_id==$m->owner_id) { // this is the organizer // notify the participants //echo 'notify participants'; foreach ($m->participants as $p) { $m->notify($m->id,$p->id); } } else { // this is a participant // notify the organizer and // to do - when there are multiple participants $m->notify($m->id,$m->owner_id); } } else { // this log entry by same actor as last continue; } } // clear the log for this meeting Meeting::clearLog($m->id); } } }
Если организатор собрания внес изменения, участник (участники) должен быть уведомлен(ы). Если участник внес изменения, организатор (и в будущем другие участники) должен быть уведомлен(ы); несколько встреч участников будут реализованы в последующих учебниках.
Создание сводки текста для логов собрания
В текущем пользовательском интерфейсе Планировщика собраний ряд зарегистрированных изменений относятся к идентичным элементам и отменяют друг друга. Например, если вы нажмете переключатель для места, сначала он отклоняется. Чтобы принять его, вам нужно нажать его еще раз. Оба изменения регистрируются.
Мне пришлось написать дополнительный код, чтобы создать краткое, точное текстовое резюме для лога.
Например, вот история действий MeetingLog. Обратите внимание на повторение действий Cloudster, которые отменяют друг друга в тех же местах и времени:

Основное текстовое представление гласит:
Cloudster добавила заметку Спасибо за напоминание. Я обязательно буду., Принял время Чт 9 июня в 12:00, принял время Пт Июн 10 в 12:00, отклонил время Пт Июн 10 в 12:00, отклонил время Чт 9 июня в 12:00 PM, отклонено время Wed Jun 8 at 12:30 PM, отклонено место Chaco Canyon Органическое кафе, принято место Chaco Canyon Органическое кафе, отклоненное место Chaco Canyon Органическое кафе, принятое место No Bones Beach Club и отклоненное место No Bones Beach Club.
Как мы создаем простое текстовое резюме полученных изменений для электронной почты уведомления, например, показано ниже:

Внутри Meeting::notify()
мы запрашиваем историю действий для этого собрания со времени последнего уведомления:
// build the english language notification $history = MeetingLog::getHistory($meeting_id,$user_id,$mtg->cleared_at);
Вот код, который создает текстовую строку того, что произошло. Я, скорее всего, почищу этот код в будущем. Например, окончательная версия содержит правильный грамматический список с соответствующим использованием запятых.
public static function getHistory($meeting_id,$user_id,$cleared_at) { // build a textual history of events for this meeting // not performed by this user_id and since cleared_at $str =''; $events = MeetingLog::find()->where(['meeting_id'=>$meeting_id])->andWhere('actor_id<>'.$user_id)->andWhere('created_at>'.$cleared_at)->orderBy(['created_at' => SORT_DESC,'actor_id'=>SORT_ASC])->all(); $num_events = count($events); $cnt =1; $current_actor = 0; $current_str=''; $items_mentioned =[]; foreach ($events as $e) { if ($e->actor_id <> $current_actor) { // new actor, update the overall string $str.=$current_str.'<br />'; // reset the current actor's event string $current_str=''; $current_actor = $e->actor_id; $actor = MiscHelpers::getDisplayName($e->actor_id); } else { $actor = ''; } $action = $e->getMeetingLogCommand(); $item = $e->getMeetingLogItem(); if (in_array($e->item_id,$items_mentioned)) { // only mention item the first time it appears (last action, as sorted) continue; } else { $items_mentioned[]=$e->item_id; if ($actor=='') { if ($cnt == $num_events) { $current_str.=' and '.$action.' '.$item; } else { $current_str.=', '.$action.' '.$item; } } else { $current_str.=$actor.' '.$action.' '.$item; } // count events $cnt+=1; } } // add last current_str (may be empty) $str.=$current_str.'<br />'; return $str; }
По сути, getHistory() является специфичным для каждого пользователя. Следующий запрос сортирует действия в обратном порядке, потому что в основном последнее изменение имеет доминирующее влияние:
$events = MeetingLog::find()->where(['meeting_id'=>$meeting_id])->andWhere('actor_id<>'.$user_id)->andWhere('created_at>'.$cleared_at)->orderBy(['created_at' => SORT_DESC,'actor_id'=>SORT_ASC])->all();
В будущем будет много участников, чьи действия накладываются во времени, поэтому мы группируем историю с помощью actor_id
.
Затем я отслеживаю $current_actor
, когда мы создаем текстуализацию, поэтому мы упоминаем только одно имя, т. е. «Джефф сделал эти действия. Джон делал эти действия: «не« Джефф сделал это, Джон сделал это, Джефф сделал это, и Джон сделал это, и Джон сделал это ».
Точно так же я отслеживаю упоминание объектов в $items_mentioned
и игнорирую более ранние события, предоставляя только последнее доминирующее действие на месте или времени, то есть «Jeff принял No Bones Beach Club», а не «Jeff отклонил No Bones Beach Club, Джефф принял No Bones Beach Club.
Код был замысловатым и забавным для написания. Получившаяся текстуализация (показанная выше) интересна для наблюдения.
Доставка уведомления по электронной почте
В учебном пособии по переработке почтовых шаблонов я описал переход на наши новые отзывчивые шаблоны от Oxygen. Это потребовало пересмотра шаблона notify-html.php и потребует постепенного его улучшения с течением времени.
Вот выдержка из шаблона:
<tr> <td align="center" valign="top" width="100%" style="background-color: #f7f7f7;" class="content-padding"> <center> <table cellspacing="0" cellpadding="0" width="600" class="w320"> <tr> <td class="header-lg"> Changes to Your Meeting </td> </tr> <tr> <td class="free-text"> <p>Hi <?php echo Html::encode(MiscHelper::getDisplayName($user->id)); ?>, changes have been made to your meeting.</p> <p><?php echo $history; ?></p> <p>Please click the button below to view the meeting page.</p> </td> </tr> <tr> <td class="button"> <div><!--[if mso]> <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="http://" style="height:45px;v-text-anchor:middle;width:155px;" arcsize="15%" strokecolor="#ffffff" fillcolor="#ff6f6f"> <w:anchorlock/> <center style="color:#ffffff;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:regular;">My Account</center> </v:roundrect> <![endif]--><a class="button-mobile" href="<?php echo $links['view'] ?>" style="background-color:#ff6f6f;border-radius:5px;color:#ffffff;display:inline-block;font-family:'Cabin', Helvetica, Arial, sans-serif;font-size:14px;font-weight:regular;line-height:45px;text-align:center;text-decoration:none;width:155px;-webkit-text-size-adjust:none;mso-hide:all;">Visit Meeting Page</a></div> </td> </tr> </table> </center> </td> </tr>
Отправка электронной почты
Доставка электронной почты выполняется аналогично приглашениям на встречу с помощью расширения Yii2 SwiftMailer через нашу конфигурацию SMTP Mailgun.
$message = Yii::$app->mailer->compose([ 'html' => 'notify-html', 'text' => 'notify-text' ], [ 'meeting_id' => $mtg->id, 'sender_id'=> $user_id, 'user_id' => $a['user_id'], 'auth_key' => $a['auth_key'], 'links' => $links, 'meetingSettings' => $mtg->meetingSettings, 'history'=>$history, ]); if (!empty($a['email'])) { $message->setFrom(['support@meetingplanner.com'=>'Meeting Planner']); $message->setReplyTo('mp_'.$meeting_id.'@meetingplanner.io'); $message->setTo($a['email']) ->setSubject(Yii::t('frontend','Meeting Update: ').$mtg->subject) ->send(); }
Что дальше?
Надеюсь, вам понравились эти учебные пособия из двух частей. Я считаю создание журнала и текстового описания его истории сложным и интересным. И это оказалось полезным при отладке и обобщении обновлений собрания для уведомлений. Однако тестирование было непростым, так как всегда были отметки времени и фоновые задачи, которые необходимо было контролировать, чтобы проверить, работает ли код.
Попробуйте использовать функции уведомлений, планируя свою первую встречу. Вы должны получать регулярные уведомления, когда вам отвечают ваши приглашенные друзья или коллеги. Кроме того, я был бы признателен, если вы поделитесь своим опытом ниже в комментариях, меня всегда интересуют ваши предложения. Вы также можете связаться со мной в Twitter @reifman напрямую.
Я также начинаю экспериментировать с WeFunder, основываясь на реализации новых правил SEC. Пожалуйста, обратите внимание на наш профиль. Я могу написать об этом больше в этой нашей серии.
Следите за предстоящими учебными пособиями в разделе серии Пишем свой стартап на PHP. Впереди у нас есть еще несколько больших функций.
Ссылки по теме
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post