原文:http://www.symfony-project.com/askeet/2
昨天的複習
經過第一天,有點長但稍微有趣的學習,我們看到如何安裝 symfony 框架,設定一個新的程式和開發環境,然後將源碼安全的從源碼版本控制拿回來。BTW,第一天產生的源碼,已經在 askeet SVN 源碼倉庫裏:
http://svn.askeet.com/
第二天的目標,定義最終的結果應該和功能,粗略的資料模型,開始寫源碼。將會包含產生一個物件相關的映射和程式scaffolding交互的使用它來新增,讀取,修改資料庫裏的記錄, 內容也是不少,讓我們快開始吧
(askeet是一個新字,其官方網站也沒直接解釋這個字,隨後跟著ASK IT,FIND IT,ANSWER IT,發問,找答案,回答問題)
什麼是你想要知道的?那是個有趣的問題。有很多有趣的問題,如:
這些問題不會只有唯一解,最好的答案通常是萬中選一,事實上,只有一個答案的目題常是最無趣的(如,1+1=?)但是網頁只有一個解,這是不公平的
逛逛 askeet。這網站致力於幫助人們對他們的問題找答案。誰來回答這些難對付的問題?每個人皆可。每個人也可以評比別人的答案,然後最受歡迎的答案會最受注目。當一堆問題產生,要用一個分類或子分類來組織它們幾乎是不可能的事,所以提問者要會貼標籤(tag), 可用他/她想要的任何字眼。”à la” del.icio.us.當然最受歡迎的標籤會容易冒出來。
假如一個人想要追蹤一個特殊問題的答案,他/她可以訂閱這問題的 RSS feed 。這些功能必須是高雅的和輕量的,讓所有的互動不要跑到下一頁,而是一種 AJAX 的型式。最終,一個後端是需要的->處理一下垃圾問題和答案,有鼓勵性人工的推一個問題。
然後你會問:這類網站似曾相識?當然,有類似的網站,但和 faqts, eHow, Ask Jeeves 這類的網站比較,它們是少了共同的答案,沒有AJAX,沒有 RSS 沒有 tags ,所以和本站並不相同。我們是強調 web 2.0 的服務。
譯註:(web 2.0的網站目前有很多成功的範例,簡單之外,還要讓人家樂於參與,然後衝高流量,昨天(10/11),google用16億買下了youtube, 這個供大家上傳10分鐘以下短片的網站也是 當紅的web 2.0範例,也創造了不少的話題性,主要是使用者會上傳一些有版權爭議的影片,一般是認為google藉此一舉變成最大的電視台,可提供最多的節目,不用攝影棚,不用養演員,只要提供頻寬,超大的頻寬,所以南韓的寬頻基礎建設,是google下一個攻佔的目標。當紅的超女在上面應該都找得到)
Askeet最大的理想,希望不只是個網站,也是個任何人可以下載,在家或公司安裝,用力修改或新增特性。源碼也將用open-source license釋出。
你的人力資源的頭頭在找一個知識管理的系統嗎?你想要跟催修理你的車子的所有點子?你不必建一個常問問題集在你的網站?不要再找個不停,只要有 askeet 。當然,askeet將會出現,這是我們的耶誕節禮物。
你想怎麼展開一個 symfony 程式?全靠你。你可以寫故事,做個計劃,找個同伴來 pair programming (假如你是個XP熟手),或寫個仔細的規格,如果你是個UML迷,你可以畫一下所有的bjects, states, interactions。
不過,這教程不是一個程式的一般開發過程,所以我們直接用一個關聯資料庫模型來開始,然後一個接一個的加特性。重要的是,每天要有一個能跑的程式。不是龐大但還不能產出任何東西的源碼。在真實世界裏,我們將對所有特性做單元測試,但我們相信我們沒有那麼多時間做品保。有一天會專門來講單元測試,所以請繼續閱讀。
這個項目裏,我們用 MySQL 加上InnoDB 的特性,利用一致性的限制和交易的支援。一開始,我們會用 SQLite ,為了避免設定資料庫的細節,在databases.yml 要有一些修改,我們留給你研究,算是個習題。
明顯的,有’question’ , ‘answer’ 兩個表,我們也要’user’表,和’interest’表來放對某問題有興趣的人,’relevancy’是放人和答案的關係。
一個提問(回答)的人,將要提一個問題,也可以推崇一個答案,或是宣告對一個問題的興趣,提問者不一定要對上一個答案,但答案總是可以和人有關連,所以有提供熱門回答的人可以容易被識別出來,沒有指定人的答案將會是一個一般使用者的貢獻。叫匿名烏雅。這是容易被了解的用一個 entity relationship圖。
注意我們在每一個表都已經宣告一個欄位: created_at 。 created_at 可以認出這種欄位,會自動填入系統時間到這種欄位裏,當新增一筆記錄時。同理 ,updated_at也是這樣處理:當修改一筆記錄時,系統時間會自動加入這個欄位。
這個關連性的模型必須翻譯成一個讓symfony能理解的設定檔。這就是 schema.xml 的目的。放在askeet/config/ 目錄下。
有兩者方法來寫這個檔:手寫,也是我們喜歡的方式。或是從一個現存的資料庫產生。讓我們看看第一種解法。首先。我們必須要重新命名這個樣本。
$ svn rename config/schema.xml.sample config/schema.xml
schema.xml的文法是相當簡單的,在Propel 網站上有詳細的說明,這是個XML,每一個<table> tags 裏有<column>, <foreign-key> and <index>tags. 一旦你寫一個
<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noxsd="true"> <table name="ask_question" phpName="Question"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" /> <column name="user_id" type="integer" /> <foreign-key foreignTable="ask_user"> <reference local="user_id" foreign="id"/> </foreign-key> <column name="title" type="longvarchar" /> <column name="body" type="longvarchar" /> <column name="created_at" type="timestamp" /> <column name="updated_at" type="timestamp" /> </table> <table name="ask_answer" phpName="Answer"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" /> <column name="question_id" type="integer" /> <foreign-key foreignTable="ask_question"> <reference local="question_id" foreign="id"/> </foreign-key> <column name="user_id" type="integer" /> <foreign-key foreignTable="ask_user"> <reference local="user_id" foreign="id"/> </foreign-key> <column name="body" type="longvarchar" /> <column name="created_at" type="timestamp" /> </table> <table name="ask_user" phpName="User"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" /> <column name="nickname" type="varchar" size="50" /> <column name="first_name" type="varchar" size="100" /> <column name="last_name" type="varchar" size="100" /> <column name="created_at" type="timestamp" /> </table> <table name="ask_interest" phpName="Interest"> <column name="question_id" type="integer" primaryKey="true" /> <foreign-key foreignTable="ask_question"> <reference local="question_id" foreign="id"/> </foreign-key> <column name="user_id" type="integer" primaryKey="true" /> <foreign-key foreignTable="ask_user"> <reference local="user_id" foreign="id"/> </foreign-key> <column name="created_at" type="timestamp" /> </table> <table name="ask_relevancy" phpName="Relevancy"> <column name="answer_id" type="integer" primaryKey="true" /> <foreign-key foreignTable="ask_answer"> <reference local="answer_id" foreign="id"/> </foreign-key> <column name="user_id" type="integer" primaryKey="true" /> <foreign-key foreignTable="ask_user"> <reference local="user_id" foreign="id"/> </foreign-key> <column name="score" type="integer" /> <column name="created_at" type="timestamp" /> </table> </database>
注意在這個檔裏,資料庫的名稱是設成 propel ,是實際的資料庫名。這是一個參數, 被用來連接symfony 框架的 Propel 層。真實的資料庫名稱是定義在databases.yml 設定檔(請看下面)。也有另一個方法來產生 schema.xml ,假如你有一個已經存在的資料庫 ,且你也熟悉一個資料庫的設計工具,你會比較喜歡從被產生的MySQL資料庫建這個結構檔。在你這樣做之前,你只要編輯在askeet/config/的 propel.ini檔輸入你的資料庫的連接設定:
propel.database.url = mysql://username:password@localhost/databasename
在這裏 ,帳號,密碼,主機,資料庫名都是你資料庫實際上的設定值,你現在可以呼叫
$ symfony propel-build-schema
命令來產生 schema.xml
注意:有一些工具可以讓你圖形化的方式建一個資料庫(例如:Fabforce's Dbdesigner),可直接產生schema.xml (透過DB Designer 4 TO Propel Schema轉換器)
譯註: 我覺得如果舉phpmyadmin會更好,不但是圖形界面,而且是WEB界面,易用性超高,幾乎無所不能,只限於對mysql。)
請用 InnoDB 引擎,請在askeet/config/目錄下的 propel.ini 加一筆記錄
propel.mysql.tableType = InnoDB
一旦 schema.xml 建立,你可根據關係模型來建立物件模型,在 symfony ,這物件關係的映射是由 Propel 處理。封裝進 symfony 指令
$ symfony propel-build-model
上述指令(你必須在askeet項目裏的根目錄下指令)會產生 相對應於schema的表的類別,也一併產生 標準的存取器(→get() and →set()方法)你可以在askeet/lib/model/om/目錄下看產生出來的類別。
如果你發現為何每一個表有兩個類別,請去看symfony book.的 model 章節。你每次一重建模型,這些類別就會覆寫。在這個專案中發生的機會滿大的。假如你需要對一個物件模型加方法,你必 須要要進askeet/lib/model/目錄修改,這些類別繼承自/om。
現在 symfony 有一個資料庫的物件模型。該是你的項目連上MySQL的時候了, 首先,你必須要建一個資料庫。
$ mysqladmin -u youruser -p create askeet
現在打開askeet/config/databases.yml設定檔,假如這是你第一次用symfony,你將發現 symfony 設定檔是用 YAML 文法簡單,但有一個主要的約束,就是永遠不要用Tab鍵,永遠用空白鍵。一旦你了解,你可以開始把實際的連接設定寫入這個檔裏。
all: category:
all:
propel:
class: sfPropelDatabase
param:
phptype: mysql
host: localhost
database: askeet
username: youruser
password: yourpasswd
如果要知道更多。請讀 symfony book.的practice chapter
假如你不想手寫設定檔。你可能也有相對應的表在資料庫,你可以省略這一步。如果你是打字迷,這裏有個驚奇,你不需要建表和欄位,在 schema.xml 裏做一次,然後 symfony 會產生建表及欄位的指令。
$ symfony propel-build-sql
上面指令會產生一個 schema.sql (在askeet/data/sql/),將SQL執行
$ mysql -u youruser -p askeet < data/sql/schema.sql
symfony 知道之前做過的工作是有用的永遠是好的,到現在,你的瀏覽器無用武之地,我們馬上將建一個網頁程式,就讓我們建一組基本的symfony 的動作和樣板,來維護資料表。這將允許你提一些問題,並展示它們。
在這個目錄下,鍵入:
$ symfony propel-generate-crud frontend question Question
這指令產生了問題模組的scaffolding 在前端程式,根據Question Propel的物件模型,產生了基本的新增,查詢,修改,刪除的動作()。不用困惑: scaffolding 還不是一個完成的程式,是個基礎的結構,在這結構之上你可開發新特性,加上一些商業規則,修改它的外觀和感覺。
這是 用CRUD 生成子的產生的動作的列表:
| 动作 | 说明 |
|---|---|
| 列表 | 將表裏的所有記錄秀出來 |
| 索引 | 可去找列表 |
| 秀 | 對一個指定的目錄秀出所有欄位 |
| 編輯 | 秀一個表單來新增一筆記錄或編輯一筆已存在的 |
| 修改 | 根據需求的參數來修改一筆記錄,從後導向到秀 |
| 刪除 | 從表中刪除一筆指定的記錄 |
你可在 scaffolding 這章,發現更多關於生成的動作。
在這個目錄下,注意這個新問題的模型和瀏覽它的源碼。
不論何時你加入了一個 新類別,都需要被自動載入,不要忘記清掉設定的快取殘留(再重載入自動載入的快取)
$ symfony cc frontend config
你現在可以線上測試它了,
繼續往前,測試它,在一些新的問題,編輯它,列出它,刪出它,如果可運作,表示這個物件模型是正確的,連接資料庫也無誤,而關連的模型和資料庫也是正確的,這是一個良好的功能測試。
http://askeet/question
你不用寫一行PHP代碼,一下子,你有一個基礎的程式可以用了。就第二天來說,這樣還不壞,明天,我們將為了寫一歡迎網頁和列出這些問題而寫一些代碼,我們也將用批次指令加一些測試的資料到資料庫裏,並學習擴展這個模型。
測試用CRUD存取資料 現在你知道這程式將要做什麼,你也可以想像加上一些新功能。請使用 askeet mailing-list 不吝賜教,最棒的建議將變成第21天的內容。
請自由取用今天教程的源碼(標籤為) release_day_2
http://svn.askeet.com/tags/release_day_2
明天見