數據庫是關系型的,PHP5和symfony是面向對象的,為了更有效地使用面向對象方式訪問關系的數據庫系統,將面向對象的邏輯轉換到關系型邏輯是必須的。
ORM的最大優點是重用,數據對象方法可以在應用的不同部分調用,甚至不同的應用中被調用。ORM層同時也封裝了數據邏輯——比如,計算論壇用戶的等級需要用戶發布了多少信息以及發布信息的受歡迎度等等,當要在頁面顯示用戶等級的時候只需調用一個數據模型方法即可,所有復雜的邏輯業務都在方法內部實現。而且,你可以在必要的時候修改計算方式,這是只要修改數據模型方法即可,顯示部分根本無需修改。
用對象替代記錄,用類替代表還有另一個好處:對象提供的訪問屬性可以不與表字段對應。看下面的代碼:
public function getName() { return $this->getFirstName.' '.$this->getLastName(); } |
所有重復數據存儲方法和數據自身的業務邏輯都可以保存在對象中。看個購物車統計:
public function getTotal() { $total = 0; foreach ($this->getItems() as $item) { $total += $item->getPrice() * $item->getQuantity(); } return $total; } |
還有一個好處就是不同數據庫使用的SQL語法可能會有區別,從一種數據庫轉換到另一種數據庫將必須重寫SQL查詢語句(以前方式),采用抽象層與ORM將不涉及具體的SQL語句實現,只關注操作的業務本身。
Symfony使用Propel作為ORM,Propel使用Creole作為數據庫抽象,他們都是第三方組件,都有Propel小組開發。
Symfony項目中所有應用共享一個模型。模型是獨立于應用的,模型文件存儲在項目根下的lib/model目錄。
要創建數據對象模型,你不惜告訴symfony如何去影響,即需要給定一個大綱文件。在大綱文件中你定義表、字段、關系、默認值、字符集等信息。
Symfony的大綱文件采用YAML格式,必須保存在myproject/config/文件夾,名字一般為schema.yml。大綱文件也可是使用XML格式,要使用XML文件必須刪除YAML文件。
schema.yml |
propel: post _attributes: { phpName: Post } id: title: varchar(255) author_id: body: longvarchar created_at: author: _attributes: { phpName: Author } id: name: varchar(255) password: varchar(255) fullname: varchar(255) |
Schema.xml |
<?xml version="1.0" encoding="UTF-8"?> <database name="propel" defaultIdMethod="native" noxsd="true"> <table name="posts" phpName="Post"> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" /> <column name="title" type="varchar" size="255" required="true" /> <column name="author_id" type="integer" /> <foreign-key foreignTable="users"> <reference local="author_id" foreign="id"/> </foreign-key> <column name="body" type="longvarchar" /> <column name="created_at" type="timestamp" /> </table> <table name="author" phpName=" Author "> <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" /> <column name="name" type="varchar" size="50" required="true" /> <column name="password" type="varchar" size="50" required="true" /> <column name="fullname" type="varchar" size="100" /> </table> |
數據庫名稱blog不會在schema.yml文件中顯示,它定義在其他文件(database.yml和propel.ini),這有好處:通過簡單的修改數據庫鏈接即可滿足不同目的的使用,比如開發過程中使用blog_dev數據庫,測試階段使用blog_test數據庫,運行時候使用blog數據庫等等。
Schema.yml威爾建中第一個鍵表示連接名。大綱中包含多個表,每個表包含一組列。在YAML中,鍵以冒號結束,結構以縮進反應(切記不要使用tab)。表可以包含特殊屬性,比如phpName(生成后的類名),如果沒有定義phpName,symfony使用camelCase方式定義之。
【cameCase約定刪除單詞中的下劃線并將單詞的首字母大寫,比如:post表的類名為Post,blog_article的類名為BlogArticle】
表包含列信息,列值可通過三種不同方式定義:
l 如果沒有定義任何信息,symfony將依據列名和空列約定猜測最佳屬性。例如,id列將被定義為自動增長的整型,且設置為主鍵;post表中的author_id將理解為author表的外間;created_at自動設置為時間戳類型。
l 如果只定義了一個屬性則為列的類型。可接受的類型:boolean, integer, float, date, varchar(size), longvarchar (在MySQL中轉化為text)等等,如果varchar長度大于255,你應該使用longvarchar類型,longchar類型在MySQL中最大65K;時間與時間戳受限于Unix,不能保存早于
l 如果要定義其他屬性(如:默認值、非空等),你需要使用鍵值對來些,后面會介紹。
列也可以有phpName屬性,采用首字母大寫方式(Id,Title,Content等),無需覆蓋。
Schema用來建立ORM層的模型類。在命令行可以非常快速的生成:
symfony propel-build-model |
運行命令后將啟動schema分析并在lib/model/om目錄生成基本的數據模型類。你會發現,兩個表在om目錄下產生了四個文件,另外在model目錄下還有額外的四個文件,這沒有錯。
為什么在兩個目錄保留兩個版本的數據對象模型?
你可能需要在模型對象中添加自定義方法和屬性,但在項目開發過程中,你可能也要調整表以及表結構。一旦修改了schema.yml文件,你需要使用上面的命令行語句重新生成對象模型類,如果你的自定義方法和屬性寫在了生成的類中,他們將被重新生成所刪除!
基類存在lib/model/om目錄,是有schema直接生成的。你不應該修改他們。另一方面,自定義類保存在了lib/model目錄,他們繼承自基類。當調用命令行語句重新生成數據對象模型的時候,他們不會被改動,所以應該將自定義方法和屬性放這里。
Post和author是對象類,他們表示了數據庫中的記錄,提供了對記錄及相關記錄字段的訪問,也就是說可以通過調用Post對象的方法返回一條Post記錄的標題。
$post = new Post(); ... $title = $psot->getTitle(); |
PostPeer和AuthorPeer是peer類,類中包含了操作表的靜態方法。他們提供了從表獲取記錄的方法,返回對象或者對象集合。
$posts = PostPeer::retrieveByPks(array(123, 124, 125)); // $posts是Post類的對象數組 |
首先讓我們看看關系與面向對象的對應表
關系 |
面向對象 |
表 |
類 |
行、記錄 |
對象 |
字段、列 |
屬性 |
通過對象的setter與getter方法管理列值:
$post = new Post(); $post->setTitle('My first article'); $post->setBody('This is my very first article./n Hope you enjoy it!'); $title = $post->getTitle(); $body = $post->getContent(); |
一次設置多個字段需要使用fromArray()方法: