Вступление
Это руководство является частью серии « Создай свой стартап с помощью PHP» на Envato Tuts +. В этой серии я проведу вас через запуск стартапа от концепции до реальности, используя мое приложение Meeting Planner в качестве примера из реальной жизни. На каждом этапе я буду публиковать код Планировщика собраний в качестве примеров с открытым исходным кодом, из которых вы можете извлечь уроки. Я также буду решать вопросы, связанные с бизнесом по мере их возникновения
Что охватывает этот эпизод?
В этом учебном пособии мы расскажем об отправке приглашения участнику по электронной почте, реализации основного вида его содержимого и рассмотрении создания ссылок для получателей, чтобы они могли ответить.
Весь код для Meeting Planner написан на Yii2 Framework для PHP. Если вы хотите узнать больше об Yii2, ознакомьтесь с серией моих параллельных программ по программированию на Yii2 в Envato Tuts +.
Просто напоминание, я участвую в комментариях ниже. Мне особенно интересно, если у вас есть другие подходы, дополнительные идеи или вы хотите предложить темы для будущих уроков. Вы также можете связаться со мной в Twitter @reifman .
Требования к доставке приглашений
Очень интересно достичь этой стадии доставки первых приглашений, но это все еще требует большой работы. В последнем эпизоде я обновил представления собраний, чтобы они могли поддерживать либо организатора, либо участников.
Большая часть работы в этом эпизоде будет сосредоточена на создании электронных писем HTML в Yii и их доставке программно. Однако, когда я начал писать код для этого, я столкнулся со всеми сложностями, которые система должна вскоре поддержать. Например, все ссылки в приглашениях необходимы для безопасной аутентификации участников, учитывая, что они никогда не регистрировались в Meeting Planner. Часть этого я сохраню для следующего эпизода.
По сути, мы должны уведомить приложение о том, кто просматривает страницу собрания, а затем настроить внешний вид и доступные команды. Yii делает большую часть этого довольно простым, но в нем много деталей.
Краткая оговорка об опыте пользователя
Прежде всего позвольте мне сказать, что на пути к созданию минимально жизнеспособного продукта (MVP) потребуется много времени для доработки и доработки пользовательского опыта. Большая часть того, что я сейчас создаю, — это основная функциональность, позволяющая запустить альфа-версию для реального использования. Я знаю, что это выглядит грубым в некоторых местах и не всегда будет казаться таким интуитивным, как вы хотите. Есть также недостатки кодирования, которые необходимо будет оптимизировать в будущем.
Пожалуйста, не стесняйтесь оставлять свои мысли и комментарии ниже, и я буду принимать их во внимание для дальнейшей работы.
Вот некоторые из проблем, которые возникли с работой этого эпизода:
- Основной дизайн и содержание приглашения по электронной почте
- Как будут доставляться приглашения? например, какая платформа электронной почты или провайдер?
- Какие связанные команды будут предложены в письме? И сможет ли организатор ограничить некоторые полномочия, предоставляемые участникам?
- Функциональный ответ на связанные команды в приглашении по электронной почте
- Управление посещениями приглашенных пользователей, которые еще не зарегистрировались, например, что они могут получить и не могут?
- Обработка пользовательского опыта для сбора дружественных имен от посетителей
- Регистрация ответов на приглашение на собрание, а затем наращивание возможностей мониторинга и уведомлений для информирования организатора.
- Планирование инфраструктуры для будущих электронных писем, показывающих обновления по мере изменения конфигурации собрания и по мере того, как время приближается (и проходит), например, уведомления об изменениях, напоминания о собраниях, принятие ответов в виде новых заметок и т. Д.
Когда я писал код для этого эпизода, я создал некоторую инфраструктуру для некоторых из вышеперечисленных пунктов и оставил некоторые из них для обсуждения в будущих эпизодах. Для начала давайте погрузимся в дизайн приглашения.
Дизайн приглашения и содержание
Сначала я должен был спросить, что должно быть включено в электронное письмо? Очевидно, были бы стандартные поля:
- к
- Из
- Тема ( вы приглашены на встречу! )
- Тело сообщения
- нижний колонтитул
Содержание тела должно включать:
- Детали встречи
- Предлагаемые места
- Предлагаемые даты и время
И, в зависимости от настроек органайзера, какие командные ссылки должны быть представлены? Вот несколько вопросов, которые возникли. Должны ли мы разрешить получателям:
- Принять каждый вариант, то есть все места, даты и время являются приемлемыми
- Принять все места или все даты и время отдельно
- Принять конкретные места и конкретные даты и время индивидуально
- См карты для предполагаемых мест и в конечном итоге веб-сайтов и ссылок Yelp
- Отправить заметку организатору для просмотра собрания
- Предложить новое место или дату и время
- Выберите место или дату и время
- Завершить встречу
Наконец, нижний колонтитул должен будет поддерживать:
- Альфа-уведомление с запросом обратной связи
- Возможность заблокировать отправителя
- Возможность отписаться от будущих приглашений Планировщика собраний
- Информация о компании и контактная информация
Я знаю, что все это может быть сложно визуализировать — это был непростой эпизод для создания. Вот пример приглашения, которое я в конечном итоге создал:
На данный момент я использовал команды, приемлемые и отклоняющие, чтобы указать участнику, что они просто указывают, работает ли для них место или дата и время или нет. Однако для простоты я предложил Примите все места и время , примите все места и примите все время, чтобы управлять этим в более быстрых шагах.
Все это в значительной степени основано на фактической форме приглашения на встречу из последнего эпизода. Ниже вы можете увидеть часть приглашения, которая предлагает конфигурацию мест и времени:
Обратите внимание, что электронная почта предоставляет некоторые расширенные функциональные возможности, которые были созданы в последнем эпизоде, что позволяет организаторам предлагать участникам расширенные уровни контроля, такие как предложение новых мест и времени, выбор конечного места и времени и т. Д.
Мне очень быстро стало очевидно, что в будущем потребуются дополнительные инвестиции в разработку электронной почты и предложение более простых конфигураций приглашения. Опять же, мне придется сохранить это для будущих эпизодов.
Например, один из моих первых друзей по альфа-тестированию предложил, чтобы они могли указать, что некоторые места работают только в определенные даты и время, и наоборот. В конечном счете, мне может понадобиться объединить места, даты и время в одну модель выбора.
А пока давайте рассмотрим, как я доставил вышеупомянутое приглашение, как оно есть.
Доставка приглашения
Что происходит, когда организатор нажимает кнопку Отправить ? Сначала я ожидал, что мне придется писать напрямую в API Mailgun, который я изучал в предыдущих уроках Envato Tuts + . Тем не менее, поддержка электронной почты в Yii2 довольно обширна , и я смог использовать встроенную поддержку представлений для макетов электронной почты (как HTML, так и текста) и просто доставить их с помощью аутентификации моей учетной записи Mailgun SMTP. Это даже поддерживает прикрепление файлов будущих событий (.ics) для импорта собраний в календари.
Примечание: я большой поклонник Mailgun, но я также занимался разработкой для них в качестве консультанта и написал для их блога и Envato Tuts + .
Прежде чем продолжить, я призываю вас взглянуть на документацию по рассылке Yii2 . Он предлагает отличный обзор.
Сначала я добавил более подробные параметры конфигурации SwiftMailer в /common/config/main-local.php:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<?php
return [
‘components’ => [
‘db’ => [
‘class’ => ‘yii\db\Connection’,
‘dsn’ => ‘mysql:host=localhost;dbname=mp’,
‘username’ => ‘xxxxxxxxxxxx’,
‘password’ => ‘xxxxxxxxxxxx’,
‘charset’ => ‘utf8’,
],
‘mailer’ => [
‘class’ => ‘yii\swiftmailer\Mailer’,
‘viewPath’ => ‘@common/mail’,
//comment the following array to send mail using php’s mail function
‘transport’ => [
‘class’ => ‘Swift_SmtpTransport’,
‘host’ => ‘smtp.mailgun.org’,
‘username’ => ‘[email protected]’,
‘password’ => ‘axxxxxxxxxxxxxxxxxxxxxxxx2’,
‘port’ => ‘587’,
‘encryption’ => ‘tls’,
],
// send all mails to a file by default.
// ‘useFileTransport’ to false and configure a transport
// for the mailer to send real emails.
‘useFileTransport’ => false,
],
],
];
|
Это позволило компоненту Yii SwiftMailer доставлять мои электронные письма через базовый SMTP-сервис Mailgun .
Вам необходимо получить настройки SMTP Mailgun из панели управления вашего домена:
Конечно, вы также должны убедиться, что SwiftMailer является частью вашей конфигурации файла composer.json, прежде чем запускать composer update
:
1
2
3
4
5
6
|
«minimum-stability»: «stable»,
«require»: {
«php»: «>=5.4.0»,
«yiisoft/yii2»: «>=2.0.7»,
«yiisoft/yii2-bootstrap»: «*»,
«yiisoft/yii2-swiftmailer»: «*»,
|
Затем я создал конфигурацию файла представления для использования SwiftMailer. Во-первых, должен быть основной макет для HTML и текста. Затем должны быть отдельные файлы контента для каждого:
Не все это полностью задокументировано для Yii, так что, надеюсь, этот пример предложит некоторые рекомендации. Обратите внимание, что файлы вида finalize-html и -text были добавлены позже для будущего эпизода.
Как правило, файл layouts / html.php довольно прост:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<?php
use yii\helpers\Html;
/* @var $this \yii\web\View view component instance */
/* @var $message \yii\mail\MessageInterface the message being composed */
/* @var $content string main view render result */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml»>
<head>
<meta http-equiv=»Content-Type» content=»text/html; charset=<?= Yii::$app->charset ?>» />
<style type=»text/css»>
.heading {…}
.list {…}
.footer {…}
</style>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<?= $content ?>
<div class=»footer»>With kind regards, <?= Yii::$app->name ?> team</div>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
|
Тем не менее, я многое добавил к нему, чтобы начать работать со стилем и форматированием электронных писем в формате HTML, предлагаемых сообществу открытого исходного кода Mailchimp .
Yii’s SwiftMailer, как правило, автоматически конвертирует ваш HTML-вид в текст-совместимые для вас. Скорее всего, я буду хотеть более короткое и более простое текстовое представление для приглашений, но сейчас я собираюсь отложить просмотр результатов моего кода, основанных на текстовой электронной почте.
В модели Meeting.php я написал функцию отправки, которая собирает все данные, необходимые для построения моего представления приглашения, показанного выше. На данный момент я опускаю части, связанные со следующим эпизодом для создания командных ссылок. В основном я использую Yii :: $ app-> mailer compose () и send () :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public function send($user_id) {
…
foreach ($this->participants as $p) {
…
// send the message
$message = Yii::$app->mailer->compose([
‘html’ => ‘invitation-html’,
‘text’ => ‘invitation-text’
],
[
‘meeting_id’ => $this->id,
‘noPlaces’ => $noPlaces,
‘participant_id’ => 0,
‘owner’ => $this->owner->username,
‘user_id’ => $p->participant_id,
‘auth_key’ => $auth_key,
‘intro’ => $this->message,
‘links’ => $links,
‘header’ => $header,
‘places’ => $places,
‘times’ => $times,
‘notes’ => $notes,
‘meetingSettings’ => $this->meetingSettings,
]);
// to do — add full name
$message->setFrom(array(‘[email protected]’=>$this->owner->email));
$message->setTo($p->participant->email)
->setSubject(Yii::t(‘frontend’,’Meeting Request: ‘).$this->subject)
->send();
}
…
|
Эти функции создают сообщение с использованием нашего HTML-макета и просмотра, а затем передают полученные сообщения с персонализированными данными службе SMTP Mailgun. Мы можем использовать реализацию Yii своей модели MVC для доставки электронной почты.
Проблемы с Композитором
Поскольку я использовал Composer с Yii, я часто сталкиваюсь с множеством проблем, которые трудно отследить. Чаще всего это связано с тем, что плагину «yiisoft / yii2-composer» требуется ошибка composer-plugin-api 1.0.0 , но на этот раз я столкнулся с проблемой обновления Mailgun. Последние версии Mailgun API требуют текущих обновлений для guzzle. Более ранний плагин Yii, используемый в MeetingPlanner, требовал исправленной, устаревшей версии жадности. Итак, мне пришлось настроить композитор для использования псевдонима.
По сути, я дал указание композитору синхронизировать последнюю версию guzzle, но сообщить приложению, что оно использовало более старую версию. В composer.json псевдоним выглядит так:
1
2
3
4
5
|
«yiisoft/yii2-authclient»: «~2.0.0»,
«mailgun/mailgun-php»: «~2.0»,
«guzzlehttp/guzzle»:»6.2.0 as 4.2.3″,
«php-http/guzzle6-adapter»:»1.0.0″
},
|
Я приказываю ему установить «guzzlehttp / guzzle»: «6.2.0 as 4.2.3», и это заставляет все работать хорошо, по крайней мере, в этом случае. Иногда разработчики плагинов требуют определенных версий библиотек для правильной работы. Композитор, в основном, полезен, но иногда это действительно весело.
Обновление создания собрания
Поэкспериментировав с приглашениями, я решил настроить представление создания собрания, чтобы более четко поддерживать предметную область. Это позволяет пользователям написать строку темы, как если бы они отправляли электронное письмо, чтобы пригласить кого-либо на собрание без Планировщика собраний. UX для этого нужно будет со временем повторять и упрощать.
Это обеспечивает идеальную строку темы в электронном письме для приглашения на встречу. Конечно, чтобы обеспечить это, мне пришлось расширить модель Встречи.
Я создал новую миграцию под названием extend_meeting_table_add_subject который добавил предметную область:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
use yii\db\Schema;
use yii\db\Migration;
class m160409_204159_extend_meeting_table_add_subject extends Migration
{
public function up()
{
$tableOptions = null;
if ($this->db->driverName === ‘mysql’) {
$tableOptions = ‘CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB’;
}
$this->addColumn(‘{{%meeting}}’,’subject’,’string NOT NULL’);
}
public function down()
{
$this->dropColumn(‘{{%meeting}}’,’subject’);
}
}
|
И мне пришлось добавить поддержку нового поля в файл Meeting _form.php и модель.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
<div class=»meeting-form»>
<?php $form = ActiveForm::begin();
<?= $form->field($model, ‘meeting_type’)
->dropDownList(
$model->getMeetingTypeOptions(),
[‘prompt’=>Yii::t(‘frontend’,’What type of meeting is this?’)]
)->label(Yii::t(‘frontend’,’Meeting Type’)) ?>
<?= $form->field($model, ‘subject’)->textInput([‘maxlength’ => 255])->label(Yii::t(‘frontend’,’Subject’)) ?>
<?= $form->field($model, ‘message’)->textarea([‘rows’ => 6])->label(Yii::t(‘frontend’,’Message’))->hint(Yii::t(‘frontend’,’Optional’)) ?>
<div class=»form-group»>
<?= Html::submitButton($model->isNewRecord ? Yii::t(‘frontend’, ‘Create’) : Yii::t(‘frontend’, ‘Update’), [‘class’ => $model->isNewRecord ? ‘btn btn-success’ : ‘btn btn-primary’]) ?>
</div>
<?php ActiveForm::end();
</div>
|
Вот выдержка из того, что добавлено в модель Meeting.php:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public function rules()
{
return [
[[‘owner_id’, ‘subject’], ‘required’],
[[‘owner_id’, ‘meeting_type’, ‘status’, ‘created_at’, ‘updated_at’], ‘integer’],
[[‘message’,’subject’], ‘string’]
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
‘id’ => Yii::t(‘frontend’, ‘ID’),
‘owner_id’ => Yii::t(‘frontend’, ‘Owner ID’),
‘meeting_type’ => Yii::t(‘frontend’, ‘Meeting Type’),
‘subject’ => Yii::t(‘frontend’, ‘Subject’),
‘message’ => Yii::t(‘frontend’, ‘Message’),
‘status’ => Yii::t(‘frontend’, ‘Status’),
‘created_at’ => Yii::t(‘frontend’, ‘Created At’),
‘updated_at’ => Yii::t(‘frontend’, ‘Updated At’),
];
}
|
Обновленная страница карты для мест
Изначально ссылки на мою карту приглашений шли непосредственно на Google Maps, но я понял, что было бы лучше связать их со встроенным представлением карты в Планировщике собраний, которое было частью приглашения на собрание. В моем случае я создал вид карты с помощью кнопки «Вернуться к совещанию»:
Для этого я создал новый вид, основанный на /views/place/view.php. Вот /views/meeting/viewplace.php:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
<?php
use dosamigos\google\maps\Map;
use dosamigos\google\maps\LatLng;
use dosamigos\google\maps\overlays\Marker;
use yii\helpers\Html;
use yii\widgets\DetailView;
/* @var $this yii\web\View */
/* @var $model frontend\models\Place */
$this->title = $model->getMeetingHeader();
$this->params[‘breadcrumbs’][] = [‘label’ => Yii::t(‘frontend’, ‘Meetings’), ‘url’ => [‘index’]];
$this->params[‘breadcrumbs’][] = $this->title;
$this->params[‘breadcrumbs’][] = $place->name;
?>
<h1><?php echo Html::encode($this->title) ?></h1>
<p>
<?php echo Html::a(Yii::t(‘frontend’, ‘Return to Meeting’), [‘view’, ‘id’ => $model->id], [‘class’ => ‘btn btn-primary’]) ?>
</p>
<div class=»col-md-6″>
<div class=»place-view»>
<?php echo DetailView::widget([
‘model’ => $place,
‘attributes’ => [
‘name’,
[‘label’ => ‘website’,
‘value’ => Html::a($place->website, $place->website),
‘format’ => ‘raw’],
//’place_type’,
‘full_address’,
],
]) ?>
</div>
</div> <!— end first col —>
<div class=»col-md-6″>
<?php
if ($gps!==false) {
$coord = new LatLng([‘lat’ => $gps->lat, ‘lng’ => $gps->lng]);
$map = new Map([
‘center’ => $coord,
‘zoom’ => 14,
‘width’=>300,
‘height’=>300,
]);
$marker = new Marker([
‘position’ => $coord,
‘title’ => $place->name,
]);
// Add marker to the map
$map->addOverlay($marker);
echo $map->display();
} else {
echo ‘No location coordinates for this place could be found.’;
}
?>
</div> <!— end second col —>
|
Что дальше?
Как видите, получение первого приглашения по электронной почте вызвало множество проблем и потребовало много небольших и средних обновлений. Но, имея базовую основу для них, мы можем рассмотреть сложность того, что было создано. Другими словами, что нужно дальше:
- Аутентифицированные командные ссылки. Когда участник щелкает ссылку команды в сообщении электронной почты, как мы будем аутентифицировать его, особенно если он никогда не регистрировался в нашем приложении?
- Завершение встречи на основе ответов. Когда участники делают выбор, и организатор готов завершить собрание, какие изменения и обновления необходимы для его поддержки?
- Мониторинг процесса внесения изменений участниками в приглашение. Как мы будем отслеживать изменения в деталях встречи и выбирать, когда следует уведомлять организаторов и участников?
- Уведомление организатора и участника об изменениях. Что мы должны им сказать, и какие варианты должны быть предложены, когда мы уведомим их?
- Создание файлов Календаря (.ics) для импорта в Календарь Google, Outlook и Apple Calendar с подробной информацией о приглашении. После завершения собрания мы можем отправить загружаемый файл .ics.
- Создание представления о встрече, которая полностью завершена. Как должны выглядеть детали встречи, когда ей больше не нужно предлагать команды для выбора мест и времени? Но также, какие команды необходимы для перепланирования, сдвига времени, отмены, изменения местоположения или даты и времени и т. Д.?
В следующем эпизоде мы рассмотрим некоторые из этих вопросов, сосредоточив внимание на ссылках в приглашении, на которые получатели захотят ответить, несмотря на то, что изначально они никогда не регистрировались в Meeting Planner. Другие вопросы придется подождать немного дольше.
Я также начинаю экспериментировать с WeFunder, основываясь на внедрении новых правил краудфандинга SEC . Пожалуйста, обратите внимание на наш профиль . Я могу написать об этом больше как часть этой серии.
Следите за будущими уроками в моей серии «Построение стартапа с помощью PHP» — надеюсь, вы согласитесь, что это становится захватывающим!
Пожалуйста, не стесняйтесь добавлять свои вопросы и комментарии ниже; Я обычно участвую в обсуждениях. Вы также можете связаться со мной в Twitter @reifman .