介绍
本教程是Envato Tuts +上的“ 使用PHP构建启动”系列的一部分。 在本系列文章中,我将以我的Meeting Planner应用程序作为真实示例,指导您完成从概念到现实的启动。 在此过程的每一步中,我都会将Meeting Planner代码作为开放源代码示例发布,您可以从中学习。 我还将解决与启动相关的业务问题。
此剧集涵盖了哪些内容?
在本教程中,我们将介绍通过电子邮件将邀请发送给参与者,实现其内容的基本外观以及考虑为收件人建立链接以便他们进行响应的过程。
Meeting Planner的所有代码都是在PHP的Yii2框架中编写的。 如果您想了解有关Yii2的更多信息,请在Envato Tuts +上阅读我的平行系列“ 使用Yii2编程” 。
提醒一下,我确实参与了下面的评论主题。 如果您有不同的方法,其他想法,或者想为以后的教程提出建议,我特别感兴趣。 您也可以通过Twitter @reifman与我联系 。
传递邀请的要求
达到发出第一个邀请的阶段非常令人兴奋,但仍然需要大量工作。 在上一集中 ,我更新了会议视图,以便他们可以支持组织者或参与者。
本集中的大部分工作将集中于在Yii中创建HTML电子邮件并以编程方式交付这些电子邮件。 但是,当我开始为此编写代码时,我遇到了系统必须尽快支持的所有复杂性。 例如,邀请中的所有链接都需要安全地验证参与者的身份,同时考虑他们从未注册过Meeting Planner。 其中一些我会保存在下一个情节中。
本质上,我们必须使应用程序知道谁在查看会议页面,然后自定义外观和可用命令。 Yii使这一切变得非常容易,但是涉及很多细节。
关于用户体验的简要说明
让我先说一遍,在创建最低限度可行产品(MVP)的过程中,随着时间的流逝,需要反复进行大量的用户操作和改进。 我现在正在构建的大多数功能都是使Alpha实际运行运行的核心功能。 我知道它在某些地方看起来很粗糙,而且并不总是像您想要的那样直观。 还有一些编码效率低下的问题,将来需要加以优化。
请随时在下面发表您的想法和意见,我将在正在进行的工作中考虑它们。
以下是本集的工作所带来的一些挑战:
- 邀请电子邮件的基本设计和内容
- 邀请将如何发送? 例如,哪个电子邮件平台或提供商?
- 电子邮件中将提供哪些链接的命令? 组织者是否能够限制给予参与者的某些权力?
- 对邀请电子邮件中链接命令的功能响应
- 管理尚未注册的受邀用户的访问,例如他们可以访问和不能访问的内容?
- 处理从参与者那里收集友好名称的用户体验
- 记录对会议邀请的响应,然后建立监视和通知功能以通知组织者
- 规划基础架构,以便将来的电子邮件在会议配置更改和时间临近(和过去)时显示更新,例如更改通知,会议提醒,接受答复作为新笔记等。
当我为这一集编写代码时,我为上面的某些项目构建了一些基础结构,并让其中的一些内容在以后的情节中进行了讨论。 首先,让我们进入邀请设计。
邀请函设计和内容
最初,我不得不问,电子邮件中应包含哪些内容? 显然,将存在标准字段:
- 至
- 从
- 主题( 邀请您参加会议! )
- 邮件正文
- 页脚
正文内容将需要包括:
- 会议详细
- 拟议地点
- 拟议的日期和时间
而且,根据组织者的设置,应该显示哪些命令链接? 这里有一些问题。 我们是否应允许收件人:
- 接受所有选项,即所有地点,日期和时间均可接受
- 分别接受所有地点或所有日期和时间
- 分别接受特定地点和特定日期和时间
- 查看地图以查找潜在地点,最终查看网站和Yelp链接
- 将注释发回到组织者以进行会议视图
- 建议一个新的地点或日期和时间
- 选择一个地点或日期和时间
- 完成会议
最后,页脚将需要支持:
- Alpha通知以及反馈请求
- 选择阻止发件人
- 可以取消订阅未来的会议计划者邀请
- 公司详情和联系方式
我知道将所有这些可视化可能很困难-这并非易事。 这是我最终建立的邀请的一个示例:
现在,我使用可接受的命令和拒绝的命令向参与者表明,它们只是在指示位置或日期和时间是否对他们有效。 但是,为简单起见,我提供了 接受所有地点和时间 , 接受所有地点并接受所有时间以更快地进行管理。
所有这些都是基于上一集的实际会议邀请表来进行的。 在下面,您可以看到邀请的一部分,该部分提供了地点和时间的配置:
请注意,该电子邮件提供了上一集中内置的一些高级功能,使组织者可以为参与者提供增强的控制级别,例如建议新的地点和时间,选择最终的地点和时间等。
对我来说,很快就很明显,将来需要投入更多的资金来设计电子邮件并提供更简单的邀请配置。 同样,我必须将其保存以备将来使用。
例如,我的第一个Alpha测试朋友中的一个建议他们希望他们可以指出某些地方仅在某些日期和时间有效,反之亦然。 最终,我可能需要将地点,日期和时间统一到一个选择模型中。
现在,让我们回顾一下我如何直接发送上述邀请。
传递邀请
当组织者单击“ 发送”时会发生什么? 最初,我希望我必须直接编写Mailgun API,在早先的Envato Tuts +教程中已经探讨过 。 但是, Yii2对电子邮件的支持非常丰富 ,并且我能够利用其对电子邮件布局(HTML和文本)的本机视图支持,并只需使用我的Mailgun SMTP帐户身份验证就可以提供它们。 这甚至支持附加将来的事件文件(.ics),以便将会议导入日历。
注意: 我是Mailgun的忠实拥护者,但我也以顾问的身份为他们做开发工作,并为他们的博客和Envato Tuts +撰写文章 。
在继续之前,建议您快速阅读Yii2的Mailing文档 。 它提供了一个很好的概述。
首先,我在/common/config/main-local.php中添加了更详细的SwiftMailer配置设置:
<?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' => 'xxxxxxxxxxxxxxxxxx@meetingplanner.io',
'password' => 'axxxxxxxxxxxxxxxxxxxxxxxx2',
'port' => '587',
'encryption' => 'tls',
],
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => false,
],
],
];
这使Yii的SwiftMailer组件能够通过Mailgun的基本SMTP服务传递我的电子邮件。
您需要从其控制面板的域中获取Mailgun SMTP设置:
当然,在运行composer update
之前,您还必须确保SwiftMailer是composer.json文件配置的一部分:
"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文件非常简单:
<?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() ?>
但是,我添加了很多东西来开始处理Mailchimp提供给开源社区HTML电子邮件的样式和格式。
Yii的SwiftMailer通常会自动为您将HTML视图转换为与文本兼容的视图。 很可能,我希望邀请函的文本视图更短,更简单,但是现在,我将延迟审阅代码的基于文本的电子邮件结果。
在Meeting.php模型中,我编写了一个send函数,该函数收集构建上面显示的邀请视图所需的所有数据。 现在,我将与下一集相关的部分省略,以构建命令链接。 基本上,我使用Yii :: $ app-> mailer compose()和send() :
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('support@meetingplanner.com'=>$this->owner->email));
$message->setTo($p->participant->email)
->setSubject(Yii::t('frontend','Meeting Request: ').$this->subject)
->send();
}
...
这些功能使用我们HTML布局和视图构建消息,然后将生成的带有个性化数据的消息传递给Mailgun的SMTP服务。 我们可以使用Yii的MVC模型实现来进行电子邮件传递。
作曲家的问题
当我在Yii中使用Composer时,经常会遇到很多问题,这些问题很难找到。 最常见的是,它与“ yiisoft / yii2-composer”插件相关,需要composer-plugin-api 1.0.0错误,但是这次,我遇到了更新Mailgun的问题。 Mailgun API的最新版本需要当前的更新。 MeetingPlanner中使用的较早的Yii插件需要固定的,过时的版本。 因此,我必须配置作曲家以使用别名。
本质上,我指示作曲家同步最新版本的guzzle,但告诉应用程序它使用的是旧版本。 在composer.json中,别名如下所示:
"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” ,并且至少在这种情况下,所有功能都可以正常运行。 有时,插件开发人员需要特定版本的库才能正常运行。 Composer主要是有用的,但有时肯定很有趣。
更新会议创建
在尝试邀请时,我决定自定义会议创建视图以更清楚地支持主题字段。 这使用户可以编写主题行,就好像他们在发送电子邮件邀请没有会议计划程序的会议的人一样。 随着时间的流逝,与此相关的UX需要进行迭代和简化。
这为会议邀请提供了理想的主题行。 当然,为此,我必须扩展会议模型。
我创建了一个名为 extend_meeting_table_add_subject 其中添加了主题字段:
<?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');
}
}
而且我必须在会议_form.php文件和模型中添加对新字段的支持。
<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模型的摘要:
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,但我意识到将它们链接到Meeting Planner的嵌入式地图视图会更好,这是会议邀请的一部分。 就我而言,我使用“返回会议”按钮创建了地图视图:
为此,我创建了一个基于/views/place/view.php的新视图。 这是/views/meeting/viewplace.php:
<?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日历。 会议结束后,我们可以发送可下载的.ics文件。
- 建立一个已完全完成的会议视图。 当不再需要提供用于选择地点和时间的命令时,会议详细信息应该是什么样? 但是,还需要什么命令来重新计划,时间平移,取消,更改位置或日期和时间等?
下一个情节将探讨其中的一些问题,重点是邀请者中尽管最初从未在Meeting Planner上注册的人,但仍希望答复的链接。 其他问题将需要等待更长的时间。
我还将根据SEC新的众筹规则的实施情况,开始对WeFunder进行试验。 请考虑关注我们的个人资料 。 作为本系列的一部分,我可能会对此进行更多介绍。
在“ 用PHP构建您的启动”系列中观看即将发布的教程-我希望您同意这会变得令人兴奋!
请随时在下面添加您的问题和评论; 我通常会参与讨论。 您也可以通过Twitter @reifman与我联系 。