介绍
本教程是Envato Tuts +上的“ 使用PHP构建启动”系列的一部分。 在本系列文章中,我将以我的Meeting Planner应用程序作为真实示例,指导您完成从概念到现实的启动。 在此过程的每一步中,我都会将Meeting Planner代码作为开放源代码示例发布,您可以从中学习。 我还将解决与启动相关的业务问题。
我也很高兴地宣布,会议策划者已准备好试用。 您可以发送会议邀请,收集与会人员的反馈意见并完成会议,将我今天要介绍的iCal文件导入到您的日历中。 因此, 请访问MeetingPlanner.io并尝试一下 。
此剧集涵盖了哪些内容?
在上一教程中 ,我描述了如何为开始响应电子邮件邀请的参与者(即查看会议页面或接受或拒绝某个地点或时间)构建命令链接和编码操作。
我还提到了我正在约会的一个女人如何暗示她,她不知道是否或者什么时候在没有会议策划者邀请的情况下再次见到我,我很快就提供了邀请。 然后她说,如果没有Google日历条目,她将不知道何时何地出现。 在今天的教程中,我将描述如何构建iCal功能来交付她可以成功导入的.ics文件。 有人激励开发总是很有帮助的,但通常是同事或开发经理。
提醒一下,Meeting Planner的所有代码都是在PHP的Yii2框架中编写的。 如果您想了解有关Yii2的更多信息,请查看Envato Tuts +上的并行系列“ 使用Yii2编程” 。
我确实参加了下面的评论主题,如果您有其他想法或想为以后的教程提出建议,我尤其感兴趣。 您也可以通过Twitter @reifman与我联系 。
什么是iCal文件?
定义iCalendar ,维基百科说:
iCalendar是一种计算机文件格式,它允许Internet用户通过电子邮件向其他Internet用户发送会议请求和任务,或者共享扩展名为.ics的文件。
基本上,它是一个带有.ics扩展名的文件,其中包括有关会议,组织者和与会者,日期,时间和持续时间,位置等的相关信息,所有这些格式都可以通过各种平台和日历服务识别。
尽管iCalendar具有高级功能,但在会议计划者最低可行产品(MVP)的现阶段,我想确保可以将我们安排的会议轻松导入到Google日历,Apple日历和Microsoft Outlook中,并可以通过Web邮件服务识别。 稍后我将扩展其功能。
通过早期的教程,我构建了收集所有必要信息(例如参与者,日期,时间和位置)的功能。 现在,我只需要在附件中发布事件详细信息并通过电子邮件发送即可。
生成.ics文件
我没有从头开始编写.ics代码,而是从Ahmad Amin的ics File Generator开始并对其进行了自定义。 我将代码放在/common/models/Calendar.php
。
iCal文件的不同取决于用户的身份。 换句话说,必须对它们进行个性化的交付。 首先,需要自定义返回会议计划程序的链接,以便对该特定.ics文件的持有者进行身份验证。
在会议定稿过程中,我们为每个与会者构建一个事件文件,该文件具有唯一的经过身份验证的链接:
foreach ($attendees as $cnt=>$a) {
...
$icsPath = Meeting::buildCalendar($this->id,$chosenPlace,$chosenTime,$attendees);
在会议模型中, buildCalendar
方法将生成器为每个用户所需的所有数据汇总在一起:
public static function buildCalendar($id,$chosenPlace,$chosenTime,$attendees) {
$meeting = Meeting::findOne($id);
$invite = new \common\models\Calendar();
$start_time = $chosenTime->start+(3600*7); // temp timezone adjust
$end_time = $start_time+3600; // to do - allow length on meetings for end time calculation
$sdate = new \DateTime(date("Y-m-d h:i:sA",$start_time), new \DateTimeZone('PST'));
$edate = new \DateTime(date("Y-m-d h:i:sA",$end_time), new \DateTimeZone('PST'));
$description = $meeting->message;
// check if its a conference with no location
if ($chosenPlace!==false) {
if ($chosenPlace->place->website<>'') {
$description.=' Website: '.$chosenPlace->place->website;
}
$location = str_ireplace(',',' ',$chosenPlace->place->name.' '.str_ireplace(', United States','',$chosenPlace->place->full_address));
} else {
$location ='';
}
$invite
->setSubject($meeting->subject)
->setDescription($description)
->setStart($sdate)
->setEnd($edate)
->setLocation($location)
->setOrganizer($meeting->owner->email, $meeting->owner->username);
foreach ($attendees as $a) {
$invite
->addAttendee($a['email'], $a['username'])
->setUrl(\common\components\MiscHelpers::buildCommand($id,Meeting::COMMAND_VIEW,0,$a['user_id'],$a['auth_key']));
}
$invite->generate() // generate the invite
->save(); // save it to a file;
$downloadLink = $invite->getSavedPath();
return $downloadLink;
}
如果有位置(用于面对面会议),我会提供一个指向该位置网站的链接(如果有)以及嵌入式地图的地址。 为了简单起见,我决定以UTC格式编码日期和时间。
设置普通会议信息,然后添加组织者和与会者。
样本文件完成后的外观如下:
BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
UID:9832@meetingplanner.io
DTSTART:20160506T013000Z
DTEND:20160506T023000Z
DTSTAMP:20160506T013000Z
ORGANIZER;CN=admin:mailto:jeff@lookahead.io
URL;VALUE=URI:http://localhost:8888/mp/index.php/meeting/command?id=45&cmd=10&actor_id=1&k=ESxJU_2ZRhZIgzHFyJAIiC39RhZuLiM_&obj_id=0
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=robsmith;X-NUM-GUESTS=0:mailto:robsmith@lookahead.me
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=admin;X-NUM-GUESTS=0:mailto:jeff@lookahead.io
CREATED:
DESCRIPTION:It was fun running into you - let's definitely grab that beer! Website: http://www.patxispizza.com/
LAST-MODIFIED:20160506T013000Z
LOCATION:Patxi's Pizza Ballard 5323 Ballard Ave NW Seattle WA 98107
SUMMARY:Meetup for Pizza and Long Delayed Conversation
SEQUENCE:0
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
传递.ics文件作为附件
在之前的教程中 ,我描述了如何将Yii2的内置邮件支持与SwiftMailer扩展一起使用来传递会议邀请。 对于传输交付,我使用了Mailgun的 SMTP服务集成。
当然,过去,将附件集成到邮件中很复杂,但是现在使用Yii变得非常容易。 这是将文件添加到出站会议邀请中的代码:
// send the message
$message = Yii::$app->mailer->compose([
'html' => 'finalize-html',
'text' => 'finalize-text'
],
[
'meeting_id' => $this->id,
'noPlaces' => $noPlaces,
'participant_id' => 0,
'owner' => $this->owner->username,
'user_id' => $a['user_id'],
'auth_key' => $a['auth_key'],
'intro' => $this->message,
'links' => $links,
'header' => $header,
'chosenPlace' => $chosenPlace,
'chosenTime' => $chosenTime,
'notes' => $notes,
'meetingSettings' => $this->meetingSettings,
]);
$icsPath = Meeting::buildCalendar($this->id,$chosenPlace,$chosenTime,$attendees);
$message->setFrom(array('support@meetingplanner.com'=>$this->owner->email));
$message->attachContent(file_get_contents($icsPath), ['fileName' => 'meeting.ics', 'contentType' => 'text/plain']);
$message->setTo($a['email'])
->setSubject(Yii::t('frontend','Meeting Confirmed: ').$this->subject)
->send();
我只需要使用上面返回的$icsPath
并使用attachContent
方法将其包含在邀请电子邮件中。
到达Gmail时的外观如下:
当我在Mac OS中打开邀请文件时,Apple Calendar提出了第一步,选择一个日历来将事件添加到:
这是我日历的日视图中的样子:
添加事件后,单击该事件将如下所示:
总体而言,事件生成仅是相当少量的工作,并且在其实现中取得了成功。 Alpha员工印象深刻,我们将其用于实际的面对面会议。
开发中的问题
当我学习.ics并进行试验时,我在FastMail上的网络邮件帐户仅间歇性地将我的.ics文件识别为日历邀请。 我需要更新包含的属性,以便以友好的方式进行识别。
.ics文件内容的更正确结构使FastMail能够自动识别附件:
不幸的是,它的“ 添加到日历”按钮链接到它自己的日历,我没有使用。 同样,要像添加Gmail一样添加到Apple Calendar,我必须下载并打开.ics文件。
Mac OS似乎一打开就识别出这些文件。 这将引导我完成创建Apple Calendar事件的几个步骤(如上所示)。
我还需要为事件设置唯一的ID,以便将来可以发送更新。 现在,我们的数据库会议ID为'@ meetingplanner.io'就足够了,例如uid = 23522@meetingplanner.io。
要确保时区以.ics文件格式正确交付,还需要进行一些额外的研究。 为简单起见,我依靠Amin的ics生成器以UTC格式编码日期和时间。 我在Meeting Planner中还有更多工作要管理用户的时区。
我也没有从会议计划器中保留时间和结束时间。 这将是我必须尽快修补的问题,可能只是为普通会议增加了一个持续时间(以小时为单位),并允许人们根据需要进行扩展。
未来的问题
最终,我希望Meeting Planner使用更多范围的iCal功能。 最初,我只是想让MVP能够使用核心功能。 以下是一些想法。
我可能想在Meeting Planner中创建一个用户设置,该设置会将警报添加到人们的日历条目中。 在iCal中,这称为VALARM
,例如:
BEGIN:VALARM
TRIGGER:-PT1440M
ACTION:DISPLAY
DESCRIPTION:Reminder
END:VALARM
当人们更新原始事件时,即使最终事件尚未确定,我也会希望在他们的日历中支持该事件的更新。 这需要交付具有相同UID
但具有增量SEQUENCE
的VEVENT
(通过TutorialsBag ):
BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VEVENT
UID:vicky@tutorialsbag.com
DTSTART:20130617T050000Z
DTEND:20130617T075900Z
DTSTAMP:20130616T050000Z
ORGANIZER;mailto:chvivek10@gmail.com
DESCRIPTION:The is a test invite for you to see how this thing actually works
LAST-MODIFIED:20130616T050000Z
LOCATION:Queens, New York
SUMMARY:Test Demo Invite
SEQUENCE:1
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
目前,我没有跟踪更新的顺序字段。
我还希望支持从日历中删除事件的取消文件。 因此,如果某人通过Meeting Planner取消,我们将向与会者发送一个iCal文件,该文件将从其日历中删除该事件:
METHOD:CANCEL
STATUS:CANCELLED
随着时间的推移,我想为每个事件和参与者缓存.ics文件以解决性能和存储问题。 我想提供一些文件管理来减少存储这些磁盘所需的最终磁盘空间,因为它们仅需要很短的时间,并且可以根据需要轻松地重新生成。
我还想确保这些文件的存储目录是安全的,以免受到损害,因为它们包括许多个人和私人信息,例如电子邮件地址,以及在特定时间可以找到特定人员的确切位置。
将来,我还想尝试集成iCal较少使用的高级功能,以直接连接到Meeting Planner。 例如,我们将能够使用Meeting Planner的编程界面从您的iCal日历程序中取消或重新安排会议,而不必返回到Meeting Planner网站。
下一步是什么?
在“ 使用PHP构建您的启动”系列中观看即将发布的教程。 在下一个情节中,我将描述如何通过Google,Facebook和Twitter添加对注册的支持,以及如何将现有帐户连接到这些社交网络,以加快采用速度并简化使用。
同样,Meeting Planner已准备就绪,可以开始使用。 尝试一下并立即安排会议!
请随时在下面添加您的问题和评论; 我尝试定期参加讨论。 您也可以通过Twitter @reifman与我联系 。
我还将根据SEC新的众筹规则的实施情况,开始对WeFunder进行试验。 请考虑关注我们的个人资料 。 作为本系列的一部分,我可能会对此进行更多介绍。