首頁 > FLEX, PHP, 程式設計, 網頁設計 > FLEX on PHP , ZendAMF 的魔力 ValueObject 對應

FLEX on PHP , ZendAMF 的魔力 ValueObject 對應

2009年3月21日  瀏覽次數 : 7,478

在學習各種的 FRAME WORK 一定常常聽到 MVC 這個名詞,他的意思是將 資料,控制,檢視 三個不同的行為分開處理,如果要做到這樣, Value Object 就是一個很重要的東西了,在資料層面來說你應該把資料放入 Value Object ( 之後簡稱為 VO ) 中,然後再交給各種控制元件或是檢視元件來做處理,ZendAMF 可以很快速的幫我們完成這件事情。

image圖片 : 看起來很簡單,但是卻是開發大專案很重要的喔,也是 ZENDAMF 提供的好功能


NOTE :

實作本篇文章之前,請先閱讀本站 ZENDAMF 其他相關文章,因為設定會照著之前的設定來實作,謝謝,高手可以忽略,謝謝。

Value Object 可能很多人很陌生,其實並不用太害怕,JAVA 用多的人應該對他也很熟悉,簡單的說,他就是一個預先寫好的 OBJECT,並且設定好屬性,這個定義好的屬性,未來就可以讓許多不同的元件使用,並且資料內容是一致的。

舉個例來說吧,index.mxml 是我們的主程式,在主程式中我們包含了很多不同的應用系統,A系統,B系統,C系統,當使用者登入後,在取得使用者的資料後 ( 除了帳號之外還有其他大約 10 個項目的資料 ),這時候你該如何在 A B C 三個系統都可以取得使用者的資料呢 ? 是每個系統都利用使用者的 ID 去資料庫在取得一次內容嗎 ? 還是將 10 個字串一個一個傳入 A B C 三個系統 ? 還是會透過取得上層物件的方式 ? 又或許你可以 NEW 一個 OBJECT 來存放使用者資料,但是這樣 A B C 三個系統會知道 OBJECT 內有甚麼屬性可用嗎 ? 是的 , 類似 NEW 一個 OBJECT ,只是我們先將他取個名字,並且幫他定義好屬性,這樣子我們在取用的時候,是不是就知道裡面有甚麼東西了呢。

簡單的 VO 寫法 vo.as

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
package
{
	public class vo
	{
		public var user_id:String;
		public var user_name:String;
		public var user_age:int;
		//諸如此類屬性
	}
}

這個時候我們在取用的時候就會出現屬性可以使用。

image 圖片 : 終於我們不用再猜人家給我們的 OBJECT 裡面到底放了甚麼

那這個東西又跟 ZENDAMF 扯上什麼關係了,老實說,今天我為了這個問題卡了一天,但是事實上我是打錯字了,卻被卡了一天,真的是覺得自己能力太差了,好了,離題了,以前,我們不用 ZENDAMF ,我們使用 AMFPHP 來寫這種從資料庫取回資料的程式,FLEX 向 AMFPHP 要求使用者資料,AMFPHP 回傳 Result 給 FLEX ,這時候回傳的會是一個 OBJECT,我們必須一個一個的將回傳的資料塞入 VO 中,就像這樣。

1
2
3
4
5
6
7
8
9
10
11
12
	<mx:Script>
		<![CDATA[
			import mx.rpc.events.ResultEvent;
 
			public function resultHandler(event:ResultEvent):void{
				var myVO:vo = new vo();
				myVO.user_id = event.result.user_id;
				myVO.user_name = event.result.user_name;
				myVO.user_age = event.result.user_age;
			}
		]]>
	</mx:Script>

還好我們只有三個屬性,如果有 30 個你不就要哭了,難道用 VO 就應該這麼累嗎 ? 其實使用 ZENDAMF 你有更快速的綁定 ActionScript 與 PHP 之間的 VO。我看了原廠的說明,他提供了三個方式來綁定 VO ,真的是有看沒有懂,不過還好最後找到了作者的一段影片,才恍然大悟我有一個地方打錯字。

ZENDAMF 提供了三種方式綁定

  • 第一種,你可以在 GATEWAY 上設定你的 CLASSMAP

    1
    2
    
    // Map the ActionScript class 'ContactVO' to the PHP class 'Contact':
    $server->setClassMap('ContactVO', 'Contact');
  • 第二種,你可以在 PHP VO 上加上參數

    public $_explicitType = 'ContactVO';

    1
    2
    3
    4
    
    class Contact
    {
        public $_explicitType = 'ContactVO';
    }
  • 第三種,你可以在 PHP VO 上增加一個動態的方法

    1
    2
    3
    4
    5
    6
    7
    
    class Contact
    {
        public function getASClassName()
        {
            return 'ContactVO';
        }
    }

就是這三種方法,不過真的有看沒有懂,我們來做個示範練習吧。

我們建立一支程式,他會向後端 PHP 取得客戶的聯絡資料,並且放入 VO 中供其他的元件取用,首先我們先來建立 ActionScript 的 VO

ContactVO.as

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
package
{
    [Bindable]
    [RemoteClass(alias="ContactVO")]
    public class ContactVO
    {
        public var id:int;
        public var firstname:String;
        public var lastname:String;
        public var email:String;
        public var mobile:String;
    }
}

接下來我們建立好 MXML 的主程式,我們建立兩個按鈕,一個按鈕取得客戶資料並且放入 VO 中,另一個按鈕我們將 VO 的資料送回 ZENDAMF 處理過後再回傳。

UseVOtest.mxml

1
2
3
4
5
6
7
8
9
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
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" fontSize="14">
	<mx:Script>
		<![CDATA[
			import mx.rpc.events.ResultEvent;
			[Bindable]
			private var contactVo:ContactVO = new ContactVO();
 
			private function getCustomerData():void{
				this.ro1.getCumstomer();
			}
			private function reSetCustomerData():void{
				this.ro1.setCustomer(this.contactVo);
			}
			private function resultHandler(event:ResultEvent):void{
				this.contactVo = event.result as ContactVO;
 
			}
		]]>
	</mx:Script>
 
	<mx:RemoteObject id="ro1" endpoint="allgateway.php" destination="zend" source="Customer" result="resultHandler(event)"/>
	<mx:Form width="600">
		<mx:FormItem label="編號">
			<mx:Label text="{this.contactVo.id}"/>
		</mx:FormItem>
		<mx:FormItem label="姓">
			<mx:TextInput text="{this.contactVo.firstname}"/>
		</mx:FormItem>
		<mx:FormItem label="名">
			<mx:TextInput text="{this.contactVo.lastname}"/>
		</mx:FormItem>
		<mx:FormItem label="電子郵件">
			<mx:TextInput text="{this.contactVo.email}"/>
		</mx:FormItem>
		<mx:FormItem label="行動電話">
			<mx:TextInput text="{this.contactVo.mobile}"/>
		</mx:FormItem>
		<mx:FormItem>
			<mx:Button label="取得原始資料" click="getCustomerData()"/>
			<mx:Button label="取得修改後資料" click="reSetCustomerData()"/>
		</mx:FormItem>
	</mx:Form>
</mx:Application>

接下來我們來建立對應到 PHP 的 VO CLASS ,並且我們加上參數對應到 AS 的 VO CLASS 名字。

services\ContactVO.php

1
2
3
4
5
6
7
8
9
10
11
<?php
 
class ContactVO{
	public $id = 0;
    public $firstname ="";
    public $lastname ="";
    public $email ="";
    public $mobile ="";
 
}
?>

最後我們來建立主要的 CUSTOMER 取得客戶資料的 PHP CLASS 吧,因為是範例,我們就不真正從資料庫取出資料了,我們新增一個 PHP VO 然後我們給他一些假的資料,並且回傳給 FLEX , 至於重設客戶資料的方法,我們也不寫入資料庫囉,我們把取得的 VO 修改一下內容,再重新丟回給 FLEX 就可以了。

services\Customer.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
require_once 'ContactVO.php';
class Customer {
 
	function getCumstomer(){
		$contact = new ContactVO();
		$contact->id = 1;
		$contact->firstname = "Ausir";
		$contact->lastname = "Lo";
		$contact->email = "程式逗設計@corausir.org";
		$contact->mobile = "8825252";
		return $contact;
	}
	function setCustomer($contact){
 
		$contact->id = 999;
		$contact->firstname = $contact->firstname." 修改完成";
		$contact->lastname = $contact->lastname." 修改完成";
		$contact->email = $contact->email." 修改完成";
		$contact->mobile = $contact->mobile." 修改完成";
 
		return $contact;
	}
}
 
?>

最後我們再來修改一下 GATEWAY 吧,因為我們使用官方建議的第一種方法,在 GATEWAY 加上 CLASSMAP ,這裡又有一個陷阱,又是我卡關的地方了,本來因為我們使用了 addDirectory 這個方法將資料夾內所有的 CLASS 都引用,但是在雙向的 VO 溝通上如果我們沒有在特別設定 SETCLASS 會造成 VO 只可以單向溝通,也就是說 VO 只可以從 PHP 新增好後丟到 FLEX ,如果 FLEX 新增好 AS 的 VO ,丟到 ZENDAMF ,這時候一定會跳錯誤死給你看,所以記得一定要兩行都加喔。我就是一開始做的時候沒有 SETCLASS 一直跳錯誤不知道為什麼。來修改之前的 allgateway.php 檔案吧。

allgateway.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
//定義 library 位置
define ('P_S', PATH_SEPARATOR);
set_include_path('.' .P_S .'library' .P_S .'../application/models/' .P_S .get_include_path());
//引入 AMF SERVER 類別
require_once 'library/Zend/Amf/Server.php';
require_once 'services/Customer.php';
$server = new Zend_Amf_Server();
//將整個資料夾都納入 SERVER 內
 
$server->addDirectory(dirname(__FILE__).'/services/');
//注意,雙向 VO 溝通一定得設定 setClass 喔 不要忘記了
$server->setClass(Customer);
//前面的字串代表 AS 的 VO 別名 , 後面的代表 PHP 的 VO CLASS
$server->setClassMap("ContactVO","ContactVO");
 
 
 
$result = $server->handle();
echo $result;
?>

都準備好了,這時候執行應該可以取得資料,並且也可以順利修改客戶資料了,實作範例。

Value Object 的用途很廣喔,請大家務必要學會啦,ZENDAMF 也差不多到這裡告一段落了,因為連官方那邊也沒有在更多的文章了,其他的用法應該都是 PHP 的用法了,謝謝各位看官的觀賞,我們下次見。

Random Posts

Loading…

:: 把這篇好文推到書籤網站與更多人分享吧 ::
  • funp
  • Hemidemi
  • YahooKimo
  • Google
  • udn
  • Haohao
  • Live

相關文章 :

Ausir FLEX, PHP, 程式設計, 網頁設計 , , , , , ,

  1. 2009年3月21日00:16 | #1

    補充說明 :

    我在把原廠提供的兩種對應方式寫法補上

    第二種

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    <?php
     
    class ContactVO{
    	//這行是方法二
    	public $_explicitType = 'ContactVO';
     
    	public $id = 0;
        public $firstname ="";
        public $lastname ="";
        public $email ="";
        public $mobile ="";
     
    }
    ?>

    第三種

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    <?php
     
    class ContactVO{
     
    	public $id = 0;
        public $firstname ="";
        public $lastname ="";
        public $email ="";
        public $mobile ="";
     
        //這是方法三
    	public function getASClassName()
        {
            return 'ContactVO';
        }
     
    }
    ?>

    三種方法選一種來寫就可以囉

    備註 : 如果選的是第二或第三種方法 setClass 那邊還是不要忘記寫喔 !! 會造成單向 VO 傳輸

  2. 2009年3月21日00:23 | #2

    延伸閱讀 :

    Flex and PHP: remoting with Zend AMF
    Zend_Amf-classmapping 影片實作範例

    實用技巧 :

    如果你是 VO 的老手,或是新手要進階了,每次都要新增一堆變數
    如果寫的正式一點還不可以把屬性寫成 PUBLIC
    要寫 PRIVATE 並且透過 SET 與 GET 來取用
    哇喔~ 這樣 10 個屬性就要 20 個方法 有沒有這麼累阿~~

    請看這位美女達人~ 他用 AIR 幫你寫了一個自動產生 AS 的 VO 程式喔~
    非常的好用呢~ 省力不少~
    請到這邊來
    [AIR] Value Object classes creator 提供者 Erin Lin

    不知道他改天會不會開發 PHP 版 XD 偷笑中~@@ 難道要我自己開發嗎? 哈~

  3. 小老虎
    2009年4月3日11:04 | #3

    您好!
    請問一個 vo 問題,新手一直搞不懂:
    我在這個範例(A系統)裡多加了一個 MODEL(B系統),
    在 B 系統裡,我怎麼去取出 vo 的值呢?
    我得到的都是空值,不同系統不能直接存取嗎?

    model1.mxml

    在主程式我只多了個

  4. 小老虎
    2009年4月3日11:05 | #4

    程式碼貼不上去 =.=

    @小老虎

  5. 2009年4月3日11:07 | #5

    @小老虎
    你要先將 A 系統建立起來的 VO 傳進去 B 系統
    才可以取得 A 系統所建立的 VO
    類似這樣

    ?View Code ACTIONSCRIPT
    1
    2
    3
    
    var vo:VO = new VO();
    var systemB:SystemB = new SystemB();
    systemB.setData(vo);
  6. 2009年4月3日11:08 | #6

    程式碼請用

    CODE 標籤 或是 PRE 標籤 包起來~~

  7. 小老虎
    2009年4月3日13:46 | #7

    您好!
    請問一個 vo 問題,新手一直搞不懂:
    我在這個範例(A系統)裡多加了一個 MODEL(B系統),
    在 B 系統裡,我怎麼去取出 vo 的值呢?
    我得到的都是空值,不同系統不能直接存取嗎?

    model1.mxml

    在主程式我只多了個

    其他都是沿用您的程式碼。

    我看不懂這是什麼意思?我的系統 B 就是那個 model1.mxml
    var systemB:SystemB = new SystemB();

  8. 2009年4月3日13:54 | #8

    沒關係~

    用 < 中括號 來寫 PRE 標籤

    在包你的程式碼是是看

    等等我再來刪掉

  9. 2009年4月3日13:55 | #9
    ?View Code ACTIONSCRIPT
    1
    
    <pre lang="actionscript"> 程式碼 </ pre>

    這樣寫

  10. 小老虎
    2009年4月3日14:11 | #10

    您好!
    請問一個 vo 問題,新手一直搞不懂:
    我在這個範例(A系統)裡多加了一個 MODEL(B系統),
    在 B 系統裡,我怎麼去取出 vo 的值呢?
    我得到的都是空值,不同系統不能直接存取嗎?

    model1.mxml

    在主程式我只多了個

    其他都是沿用您的程式碼。

    我看不懂這是什麼意思?我的系統 B 就是那個 model1.mxml
    var systemB:SystemB = new SystemB();

    SystemB 是從哪裡來的?

  11. 2009年4月3日14:13 | #11

    怎麼你的程式碼還是消失了呢~?@@
    詭異阿~~

    這樣子你上傳到哪邊去我來下載吧 XD

  12. 小老虎
    2009年4月3日14:18 | #12

    回覆不能使用標籤的樣子,都會無效化。
    我把<>用全型的看看。

    好!
    請問一個 vo 問題,新手一直搞不懂:
    我在這個範例(A系統)裡多加了一個 MODEL(B系統),
    在 B 系統裡,我怎麼去取出 vo 的值呢?
    我得到的都是空值,不同系統不能直接存取嗎?

    model1.mxml

    <?xml version=”1.0″ encoding=”utf-8″?>
    <mx:Module xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”vertical” width=”100%” height=”100%”>
    <mx:Script>
    <![CDATA[
    import vo.ContactVO;

    [Bindable]
    private var contactVo:ContactVO = new ContactVO();

    ]]>
    </mx:Script>

    <mx:Form width=”600″>
    <mx:FormItem label=”編號”>
    <mx:Label text=”{this.contactVo.id}”/>
    </mx:FormItem>
    <mx:FormItem label=”姓”>
    <mx:TextInput text=”{this.contactVo.firstname}”/>
    </mx:FormItem>
    <mx:FormItem label=”名”>
    <mx:TextInput text=”{this.contactVo.lastname}”/>
    </mx:FormItem>
    <mx:FormItem label=”電子郵件”>
    <mx:TextInput text=”{this.contactVo.email}”/>
    </mx:FormItem>
    <mx:FormItem label=”行動電話”>
    <mx:TextInput text=”{this.contactVo.mobile}”/>
    </mx:FormItem>
    </mx:Form>

    </mx:Module>

    在主程式我只多了個

    其他都是沿用您的程式碼。

    我看不懂這是什麼意思?我的系統 B 就是那個 model1.mxml
    var systemB:SystemB = new SystemB();

    SystemB 是從哪裡來的,怎麼去定義?

  13. 小老虎
    2009年4月3日14:21 | #13

    主程式只加了個
    <mx:ModuleLoader id=”mod1″ url=”model1.swf”/>

  14. 2009年4月3日14:22 | #14

    我誤會你的意思~
    我以為你的 FLEX 有寫元件~

    你這樣寫沒有錯阿~ 是這樣取得沒有錯
    但是因為你這樣只有取出
    你的 VO 還沒有設定資料給他~ 所以取出來當然就是空值嚕

    你應該這樣

    ?View Code ACTIONSCRIPT
    1
    2
    3
    4
    5
    6
    7
    
    [Bindable]
    private var contactVo:ContactVO = new ContactVO();
     
    private function init():void{
      this.contactVo.id = 10 ;
      //...... 依此類推
    }
  15. 2009年4月3日14:27 | #15

    mx:Module 我還沒有用過

    XD 我都用元件在寫
    不過應該相差不多才是~

  16. 小老虎
    2009年4月3日14:55 | #16

    我的意思是:
    在您的範例裡已經有給 vo 值了,我就當他是[主程式 A],
    我要在[B 程式](model)直接拿來用就好了,不需再跑一次到伺服器裡取資料,
    可是使用 MODEL ,好像不能直接取主程式 A 裡的值。

    因為我想寫一個進銷存來用,用元件寫的話,檔案不是會變很大嗎?
    所以才想用 model 來做,這樣可以分開成很多小程式,需要的時候在載入就好了。

  17. 2009年4月3日15:03 | #17

    OK 了解你意思了
    先不論是 component 還是 module
    先設定 A.mxml 是 application 主程式
    B.mxml 是 component 因為 module 我不能確定
    B的寫法 你要寫一個方法來接收已經有資料的 VO

    1
    2
    3
    4
    
    private function setVO(vo:ContactVO){
        this.vo = vo ;
        // 傳入資料
    }

    而A的寫法應該在 NEW 出元件的時候丟入 VO

    1
    2
    
    b:B = new B();
    b.setVO(this.vo);

    這樣子 B 元件才拿的到 A 主程式的資料

    不知道這樣說是不是正確
    或是你要在建構的時候就丟入 VO

  18. 小老虎
    2009年4月3日15:21 | #18

    謝謝!我先試看看元件的方式吧!
    new B,這個 B 是元件 id 嗎?

  19. 2009年4月3日15:22 | #19

    不是
    我的意思是 B.mxml

    new 出來的就會是 new B();

  20. 2009年5月18日18:16 | #20

    請教一個問題…卡這關卡很久了
    若是ZendAMF要搭上CodeignIter的做法?爬文爬了很久,只找到兩篇,但都是AMFPHP配CodeignIter…
    AMF_Codeigniter_Library_No_Zend_No_Hooks_Etc

    AMF_Flash_Remoting_with_Zend_and_CI

  21. 2009年5月18日18:41 | #21

    @羊

    你好喔~
    因為我本身也沒有用過 CodeignIter 這個 FW
    不過我想如果你單純把 ZENDAMF 拿來用的話
    應該是差不多吧~~ XD

    我也是一知半解中
    或許可以討論看看 CC

  22. 2009年5月19日09:52 | #22

    @Ausir
    謝謝你!
    我再研究看看,有研究出來一定分享出來,謝謝!

  23. 2009年5月19日09:55 | #23

    @羊

    加油 ^_^”
    我今天也要開始來去再進修 FLEX 嚕…. >”<
    地獄訓練

  24. 2009年5月23日20:02 | #24

    @Ausir
    嗨,我研究出來了,成功地將ZENDAMF跟CodeIgniter整合起來了,不過礙於目前工作忙錄,可能要過一段時間才能分享出來,抱歉喔!

  25. 2009年5月23日20:13 | #25

    @羊

    你沒有把你的網址交出來 ^_^
    大家可以互相看看 CCC
    很想看你說的那套 FW 多長進長進

    我就是不長進阿 >”<…

  26. 2009年5月25日15:08 | #26

    @Ausir
    哎…… /_\
    今天在做這project時又發現問題,用codeIgniter嵌一隻swf是ok的,但這隻swf要再load外部的swf就一片空白…這是怎麼個回事呢??? /_\

  27. 2009年5月25日15:10 | #27

    @羊

    SWF 嵌入 SWF 應該是不會有問題
    可能是因為你另一個 SWF 你有用到 STAGE 屬性
    所以就錯誤了~?

  28. 2009年5月25日15:19 | #28

    @Ausir
    沒耶,我只是做簡單的測試,要利用ExternalInterface抓網址而已,而且用別的swf試過,swf從flash按ctrl + enter publish出來是讀得到,開瀏覽器 http://localhost/…. 就掛掉了 /_\ 不曉得是不是codeIgniter的問題

  29. 2009年5月25日16:10 | #29

    沒用過的 FW 所以我也不是很清楚了 >”<

  30. 2009年5月25日16:41 | #30

    @Ausir
    我…我再研究看看……..

  31. 2009年5月25日18:24 | #31

    @羊
    去PTT問了php高手終於解決了這個問題,問題出在絕對路徑與相對路徑,通常我們寫flash讀別隻swf通常都是寫相對路徑,但在codeIgniter裡是沒有相對路徑這回事,所以要用絕對路徑,把嵌swf的php裡的swf路徑改成絕對路徑,還有flash裡也改成絕對路徑就ok了!!

  32. 2009年5月25日19:06 | #32

    @羊

    原來是這樣子
    不過一般來說 MVC 的 FW 都會把路徑轉向
    所以都要稍微注意一下 SOURCE 的位址

  33. 小江
    2009年6月6日14:39 | #33

    我還是不懂$server->addDirectory(dirname(__FILE__))有什麽用。。。
    請問,這個函數到底有什麽用呢?

  34. 2009年6月6日23:59 | #34

    @小江

    這個函數的意思是說
    要把 services 這個資料夾內的所有 PHP CLASS 通通載入
    不用一隻一隻 PHP 分別載入

  35. SanC
    2009年7月30日11:53 | #35

    你好,大大有提到更進階的技巧的VO,將VO的設為private,然後再用set和get,但是,配合上zendAmf,如果AS和PHP兩個都不設定成public好像就沒辦法互傳屬性值說..還是大大有其他的方法,可以使用這更進階的技巧~^^?

  36. 2010年3月12日22:46 | #36

    你好:

    不久前像你這樣 php 回傳 class, flex 再用 class 去接,我用 amfphp 就能正確處理了~ 所有的 member variable 都是 public 的。

  37. 2010年3月15日09:27 | #37

    @SanC

    SET 跟 GET 是標準的物件導向觀念 ^^
    如果有機會我會再利用解釋看看

    @Jimmy

    嗯嗯~~
    PUBLIC 比較麻煩是如果傳入的數值需要更改過再套用
    就比較麻煩
    變成資料無法有足夠全線管控

  38. LINUS
    2010年12月19日21:08 | #38

    請問為什麼無法把這方法用在comboBox上?但我的TextInput可以用

  1. 本篇文章目前尚無任何 trackbacks 和 pingbacks。