หัวข้อนี้เราจะมาลองทำ Mini project โดยประยุกต์ใช้ Flex ร่วมกับเทคโนโลยีอื่น ซึ่งในที่นี้เราจะใช้ feature ของ Google calendar ที่สามารถส่ง SMS แจ้งเตือนกิจกรรมที่เราบันทึกไว้ได้ มาใช้ประโยชน์ โดยใช้ Library ใน Zend Frameworks ช่วยในการส่งข้อมูลจาก Flex app ไปยัง Google calendar อีกที
(ซึ่งจริงๆ ผมได้รับอนิสงฆ์จากคนที่มาเรียนแล้วเอาความรู้และการใช้งานของเทคโนโลยีตัวนี้มาให้ผมช่วยดูเพื่อเอาไปประยุกต์ใช้ ต้องขอขอบคุณมากๆ ครับ การถ่ายทอดอะไรให้กับคนอื่นก็สามารถทำให้เราได้รับความรู้ได้เช่นกัน)
ขั้นตอนหลักๆ มีดังนี้
1. Google calendar setting
2. Create PHP client access file
3. Create Flex web app
————————————-
1. Google calendar setting
ก่อนอื่นเราต้องมี gmail account ก่อน จากนั้นให้เข้าไปที่ Your_Gmail_Account > Account Settings ดังภาพ
จากนั้นเลือก My product > Calendar – Settings ดังภาพ
จะมาที่หน้า Calendar Settings ให้เลือก Mobile Setting จากนั้นตั้งค่าต่างๆ ดังนี้
Country : Thailand
Phone number : ใส่เบอร์โทรโดยใส่ระหัสประเทศนำหน้า เช่น เบอร์โทร 0879999999 ให้ใส่เป็น +66879999999
จากนั้นกดปุ่ม Send Verification Code ทาง Google ก็จะส่ง SMS เป็นหมายเลขสำหรับ Verify เพื่อรับข้อมูลการแจ้งเตือนจาก Google calendar
————————————-
2. Create PHP client access file
การติดต่อกับ Google Calendar เราจะใช้ Library ใน Zend Frameworks โดยสามารถ Download ได้ที่ http://framework.zend.com/download/latest
เมื่อเรา Download มาแล้ว Unzip แล้วนำ Zend Frameworks ไปวางไว้ที่
LocalServerApp
|-frameworks
| |-Zend
| |-…
|-your_web_root_directory_such_as_www_or_htdocs_or_public_html_etc
ตัวอย่างในรูป
จากนั้นสร้างไฟล์ PHP client access file ดังนี้
<?php
// Set up debug
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", "on");
// Set up include path for Zend Framework, this path is assuming a frameworks
// folder contains the Zend package on the same level as your public_html or www folder.
//ini_set("include_path", ini_get("include_path") . ":../frameworks");
//ini_set("include_path", ini_get("include_path") . PATH_SEPARATOR ."../frameworks");
ini_set("include_path", ini_get("include_path") . PATH_SEPARATOR . $_SERVER['DOCUMENT_ROOT'] . "/../frameworks");
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_AuthSub');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Gdata_HttpClient');
Zend_Loader::loadClass('Zend_Gdata_Calendar');
function createEvent($client, $title = 'Title', $desc='Description content', $where = 'Somewhere',
$startDateTime = '2010-01-20T00:00+07:00', $endDateTime = '2010-01-20T00:00+07:00')
{
$gdataCal = new Zend_Gdata_Calendar($client);
$newEvent = $gdataCal->newEventEntry();
$newEvent->title = $gdataCal->newTitle($title);
$newEvent->where = array($gdataCal->newWhere($where));
$newEvent->content = $gdataCal->newContent("$desc");
$when = $gdataCal->newWhen();
$when->startTime = "{$startDateTime}";
$when->endTime = "{$endDateTime}";
$reminder = $gdataCal->newReminder();
$reminder->method = "sms";
$reminder->minutes = "10";
$when->reminders = array($reminder);
$newEvent->when = array($when);
// Upload the event to the calendar server
// A copy of the event as it is recorded on the server is returned
$createdEvent = $gdataCal->insertEvent($newEvent);
return $createdEvent->id->text;
}
$user = $_REQUEST["user"];
$pass = $_REQUEST["pass"];
$service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME; // predefined service name for calendar
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$strStartDateTime = date(DATE_ATOM, mktime(date("H"), date("i") + 14, date("s"), date("m"), date("d"), date("Y")));
$strEndDateTime = date(DATE_ATOM, mktime(date("H"), date("i") + 15, date("s"), date("m"), date("d"), date("Y")));
createEvent($client, $_REQUEST["sms"],
'Title',
'Detail',
$strStartDateTime, $strEndDateTime);
echo $_REQUEST['sms'];
————————————-
3. Create Flex web app
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:views="org.robotlegs.sawasdeesms.views.*">
<s:layout>
<s:VerticalLayout paddingLeft="4" paddingRight="4" paddingBottom="4" paddingTop="4"/>
</s:layout>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<views:MainView width="{this.width}" height="{this.height}"/>
</s:Application>
MainView.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
horizontalAlign="center"
preinitialize="mainViewInit()">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.core.FlexGlobals;
import mx.events.CloseEvent;
import mx.managers.PopUpManager;
import mx.rpc.AsyncToken;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
private var arr:Array = [
{fullname:'John Doe', email:'johndoe@gmail.com', pwd:'mypassword', selected:true}
];
[Bindable] private var ac:ArrayCollection;
private var mainViewPopUp:MainPopUp;
private var hs:HTTPService;
private var urlVar:URLVariables;
private function mainViewInit():void{
ac = new ArrayCollection( arr );
hs = new HTTPService();
hs.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
hs.url = '../php_service/sms.php';
hs.addEventListener(ResultEvent.RESULT, httpServiceResult );
urlVar = new URLVariables();
}
public function onSelect(obj:Object, selected:Boolean):void{
obj.selected = selected;
ac.setItemAt( obj, ac.getItemIndex( obj ) );
}
protected function btAdd_clickHandler(event:MouseEvent):void
{
mainViewPopUp = PopUpManager.createPopUp( FlexGlobals.topLevelApplication as Sprite, MainPopUp, true ) as MainPopUp;
PopUpManager.centerPopUp( mainViewPopUp );
mainViewPopUp.addEventListener( 'formSubmit', onFormSubmit );
}
private function onFormSubmit( event:Event ):void{
if( mainViewPopUp.useForm == MainPopUp.FORM_ADD ){
ac.addItem(
{
fullname:mainViewPopUp.txtInName.text,
email:mainViewPopUp.txtInEmail.text,
pwd:mainViewPopUp.txtInPwd.text,
selected:true
}
);
}else{
ac.setItemAt(
{
fullname:mainViewPopUp.txtInName.text,
email:mainViewPopUp.txtInEmail.text,
pwd:mainViewPopUp.txtInPwd.text,
selected:dg.selectedItem.selected
},
dg.selectedIndex
);
}
}
protected function btRemove_clickHandler(event:MouseEvent):void
{
Alert.show('ต้องการลบรายชื่อ ใช่หรือไม่?', 'คำเตือน', 3, this, onConfirmRemove );
}
private function onConfirmRemove( event:CloseEvent ):void{
if( event.detail == Alert.YES ){
ac.removeItemAt( dg.selectedIndex );
}
}
protected function dg_doubleClickHandler(event:MouseEvent):void
{
mainViewPopUp = PopUpManager.createPopUp( FlexGlobals.topLevelApplication as Sprite, MainPopUp, true ) as MainPopUp;
PopUpManager.centerPopUp( mainViewPopUp );
mainViewPopUp.useForm = MainPopUp.FORM_EDIT;
mainViewPopUp.txtInName.text = dg.selectedItem.fullname;
mainViewPopUp.txtInEmail.text = dg.selectedItem.email;
mainViewPopUp.txtInPwd.text = dg.selectedItem.pwd;
mainViewPopUp.addEventListener( 'formSubmit', onFormSubmit );
}
protected function btSend_clickHandler(event:MouseEvent):void
{
urlVar.sms = txtAr.text;
urlVar.user = ac.getItemAt( 0 ).email;
urlVar.pass = ac.getItemAt( 0 ).pwd;
var token:AsyncToken = hs.send(urlVar);
token.index = 0;
}
protected function httpServiceResult( event:ResultEvent ):void{
var token:AsyncToken;
trace( event.token.index );
trace( event.result );
if( ( event.token.index + 1 ) < ac.length ){
urlVar.user = ac.getItemAt( event.token.index + 1 ).email;
urlVar.pass = ac.getItemAt( event.token.index + 1 ).pwd;
token = hs.send(urlVar);
token.index = event.token.index + 1;
}else{
Alert.show('ส่ง SMS แล้วค่ะ', 'ขอบคุณที่ใช้บริการ');
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:VGroup>
<s:HGroup width="100%" height="100%">
<mx:Spacer width="100%"/>
<mx:Button height="28" id="btAdd" icon="@Embed(source='assets/aesthetica-version-2/png/24x24/add.png')"
click="btAdd_clickHandler(event)"/>
<mx:Button height="28" id="btRemove" icon="@Embed(source='assets/aesthetica-version-2/png/24x24/remove.png')"
enabled="{dg.selectedIndex + 1}"
click="btRemove_clickHandler(event)"/>
</s:HGroup>
<mx:DataGrid id="dg" dataProvider="{ac}"
doubleClickEnabled="true" doubleClick="dg_doubleClickHandler(event)">
<mx:columns>
<mx:DataGridColumn width="200" dataField="fullname" headerText="ชื่อ - นามสกุล"/>
<mx:DataGridColumn width="200" dataField="email" headerText="อีเมล"/>
<!--
<mx:DataGridColumn dataField="selected" headerText="ส่งข้อความ ">
<mx:itemRenderer>
<fx:Component>
<mx:Box horizontalAlign="center">
<s:CheckBox id="cb" selected="{data.selected}"
change="outerDocument.onSelect(data, cb.selected)"/>
</mx:Box>
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
-->
</mx:columns>
</mx:DataGrid>
<s:HGroup width="100%">
<mx:Spacer width="100%"/>
<s:Label text="*หมายเหตุ Double-click เพื่อแก้ไข"/>
</s:HGroup>
<mx:Spacer height="50"/>
</s:VGroup>
<s:VGroup>
<s:TextArea id="txtAr" width="400"/>
<s:HGroup width="100%">
<mx:Spacer width="100%"/>
<mx:Button height="28" id="btSend" icon="@Embed(source='assets/aesthetica-version-2/png/24x24/next.png')"
label="ส่ง SMS"
click="btSend_clickHandler(event)"/>
</s:HGroup>
</s:VGroup>
</s:VGroup>
MainPopUp.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" close="titlewindow1_closeHandler(event)">
<fx:Metadata>
[Event(name="formSubmit", type="mx.events.Event")]
</fx:Metadata>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.events.CloseEvent;
import mx.managers.PopUpManager;
public static const FORM_ADD:String = 'formAdd';
public static const FORM_EDIT:String = 'formEdit';
public var useForm:String = FORM_ADD;
protected function titlewindow1_closeHandler(event:CloseEvent):void
{
PopUpManager.removePopUp( this );
}
protected function btSubmit_clickHandler(event:MouseEvent):void
{
dispatchEvent( new Event( 'formSubmit' ) );
PopUpManager.removePopUp( this );
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:controlBarContent>
<mx:Spacer width="100%"/>
<mx:Button height="28" id="btSubmit"
icon="@Embed(source='assets/aesthetica-version-2/png/24x24/accept.png')"
click="btSubmit_clickHandler(event)"/>
</s:controlBarContent>
<mx:Form>
<mx:FormItem label="ชื่อ">
<s:TextInput id="txtInName" width="200"/>
</mx:FormItem>
<mx:FormItem label="อีเมล">
<s:TextInput id="txtInEmail" width="200"/>
</mx:FormItem>
<mx:FormItem label="รหัสผ่าน">
<s:TextInput displayAsPassword="true" id="txtInPwd" width="200"/>
</mx:FormItem>
</mx:Form>
</s:TitleWindow>
————————————-
งานนี้จะเอาไปใช้อะไรได้บ้าง ก็อย่างเช่น เราไม่สามารถอยู่หน้าคอมฯ ได้ตลอด สมมติเราทำระบบสำหรับสั่งซื้อสินค้าเมื่อมีออเดอร์เข้ามาก็ส่ง SMS ให้แจ้งเตือนให้เรารู้ เพื่อจะได้บริการลูกค้าได้เร็วขึ้น หรือจะทำเป็นระบบแจ้งเตือนการนัดประชุมในองค์กรขนาดเล็ก ช่วยประหยัดค่าใช้จ่ายค่าบริการ SMS หรือจะทำเป็นแจ้งเตือนการนัดหมายกับลูกค้า ฯลฯ แล้วแต่จะเอาไปประยุกต์ แต่ก็นะของฟรี บางทีก็ missing text บ้างไรบ้าง แต่ก็ไม่หนักหนาอะไรเกินไป 😉