天天看點

symfony mysql_Symfony2學習筆記之資料庫操作

symfony mysql_Symfony2學習筆記之資料庫操作

資料庫和Doctrine

讓我們來面對這個對于任何應用程式來說最為普遍最具挑戰性的任務,從資料庫中讀取和持久化資料資訊。幸運的是,Symfony和Doctrine進行了內建,Doctrine類庫全部目标就是給你一個強大的工具,讓你的工作更加容易。

Doctrine是完全解耦與Symfony的,是以并不一定要使用它。

一個簡單例子:一個産品,我們首先來配置資料庫,建立一個Product對象,持久化它到資料庫并把它讀回來。

首先我們需要建立一個bundle:

$php app/console generate:bundle --namespace=Acme/StoreBundle

配置資料庫

在開始之前,首先需要配置資料庫連接配接資訊。根據慣例,這些資訊通常會配置在app/config/parameters.ini 檔案中。

;app/config/parameters.ini

[parameters]

database_driver=pdo_mysql

database_host=localhost

database_name=test_project

database_user=root

database_password= password

将配置資訊定義到parameters.ini檔案中也是一個常用的做法。定義在該檔案中的配置資訊将會被主配置檔案在安裝Doctrine時引用。

doctrine:dbal:driver: %database_driver%host: %database_host%dbname: %database_name%user: %database_user%password: %database_password%

通過把資料庫資訊分離到一個特定的檔案中,你可以很容易的為每個伺服器儲存不同的版本。現在Doctrine知道你的資料庫配置了,你可以用它來建立一個資料庫了。

$php app/console doctrine:database:create

建立一個實體類:

假設你建立一個應用程式,其中有些産品需要展示。即時不考慮Doctrine或者資料庫,你也應該知道你需要一個Product對象來表現這些産品。在你的AcmeStoreBundle的Entity目錄下建立一個類。

//src/Acme/StoreBundle/Entity/Product.php

namespace Acme\StoreBundle\Entity;classProduct

{protected $name;protected $price;protected $description;

}

這樣的類經常被稱為“Entity",意味着一個基礎類儲存資料。它們簡單來滿足你應用程式的業務需要。不過現在它還不能被儲存到資料庫中,因為現在它隻不過還是個簡單的PHP類。一旦你學習了Doctrine背後的概念,你可以讓Doctrine來為你建立實體類。

$php app/console doctrine:generate:entity --entity="AcmeStoreBundle:Product" --fields="name:string(255) price:float description:text"

添加映射資訊

Doctrine允許你使用一種更加有趣的方式對資料庫進行操作,而不是隻是擷取基于清單的行到數組中。Doctrine允許你儲存整個對象到資料庫或者把對象從資料庫中取出。這些都是通過映射PHP類到一個資料庫表,PHP類的屬性對應資料庫表的列來實作的。

symfony mysql_Symfony2學習筆記之資料庫操作

因為Doctrine能夠做這些,是以你僅僅隻需要建立一個meatdata,或者配置告訴DoctrineProduct類和它的屬性應該如何映射到資料庫。這些metadata可以被定義成各種格式,包括YAML,XML或者通過聲明直接定義到Product類中。

一個bundle隻可以接受一種metadata定義格式。比如,不能把YAML定義的metadata和聲明PHP實體類一起混用。

use Doctrine\ORM\Mapping asORM;

classProduct

{

protected $id;

protected $name;

protected $price;

protected $description;

}

YAML格式metadata定義:

#src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml

Acme\StoreBundle\Entity\Product:type:entity

table:product

id:id:type: integergenerator: { strategy:AUTO }

fields:name:type: stringlength: 100price:type:decimal

scale: 2description:type: text

XML格式metadata定義:

http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

表名稱是可選的,可以忽略;如果忽略将會自動的根據entity類名對應。

如果使用在類中聲明metadata需要首先使用

use Doctrine\ORM\Mapping as ORM;

導入ORM聲明字首。然後在每個聲明前使用 ORM\ 比如:

@ORM\Column(...);

注意:你的類名稱和屬性不能映射到SQL受保護的關鍵字(比如:group 或者 user)。如果你的實體類名是Group,預設情況下你的表面也将是group,這會引起SQL錯誤。當使用另外的類庫或者程式,它們使用了聲明,你應該把@IgnoreAnnotation聲明添加到該類上來告訴Symfony忽略它們。比如我們要阻止@fn 聲明抛出異常,可以這樣:

class Product

生成Getters和Setters

盡管Doctrine現在知道了如何值就花Product對象到資料庫,但是類本身還是無法使用。因為Product僅僅是一個标準的PHP類,你需要建立getter和setter方法(比如getName(),setName())來通路它的屬性(因為它的屬性是protected),幸運的是Doctrine可以為我們做這些:

$php app/console doctrine:generate:entites Acme/StoreBundle/Entity/Product

該指令可以确認Product類所有的getter和setter都被生成。這是一個安全的指令行,你可以多次運作它,它隻會生成那些不存在的getters和setters,而不會替換已有的。

關于doctrine:generate:entities指令

用它你可以生成getters和setters。

用它在配置@ORM\Entity(repositoryClass="...")聲明的情況下,生成repository類。

用它可以為1:n或者n:m生成合适的構造器。

該指令會儲存一個原來Product.php檔案的備份Product.php~。 有些時候可也能夠會造成“不能重新聲明類”錯誤,你可以放心的删除它,來消除錯誤。當然你沒有必要依賴于該指令行,Doctrine不依賴于代碼生成,想标準的PHP類,你隻需要保證它的protected/private屬性擁有getter和setter方法即可。你也可以為一個bundle或者整個實體命名空間内的所有已知實體(任何包含Doctrine映射聲明的PHP類)來生成getter和setter:

$php app/console doctrine:generate:entities AcmeStoreBundle$php app/console doctrine:generate:entities Acme

Doctrine不關心你的屬性是protected還是private,或者這些屬性是否有getter或setter。隻是以生成這些getter或者setter完全是因為你需要跟你的PHP對象進行交流需要它們。

建立資料庫表和模式

現在我們有了一個可用的Product類和它的映射資訊,是以Doctrine知道如何持久化它。當然,現在Product還沒有相應的product資料庫表在資料庫中。幸運的是,Doctrine可以自動建立所有的資料庫表。

$php app/console doctrine:schema:update --force

說真的,這條指令是出奇的強大。它會基于你的entities的映射資訊,來比較現在的資料庫,并生成所需要等新資料庫的更新SQl語句。換句話說,如果你想添加一個新的屬性映射中繼資料到Product并運作該任務,它将生成一個alert table 語句來添加新的列到已經存在的product表中。

一個更好的發揮這一優勢的功能是通過migrations,它允許你生成這些SQL語句并存儲到一個合并類,并能有組織的運作在你的生産環境中有效的跟蹤和并安全的合并你的資料庫。

現在你的資料庫中有了一個全功能的product表,它的每個列都會被映射到你指定的中繼資料。

持久化對象到資料庫

現在我們有了一個Product實體和與之映射的product資料庫表。你可以把資料持久化到資料庫裡。在Controller内,它非常簡單。添加下面的方法到bundle的DefaultController中。

//src/Acme/StoreBundle/Controller/DefaultController.php

useAcme\StoreBundle\Entity\Product;useSymfony\Component\HttpFoundation\Response;//...

public functioncreateAction()

{$product = newProduct();$product->setName('A Foo Bar');$product->setPrice('19.99');$product->setDescription('Lorem ipsum dolor');$em = $this->getDoctrine()->getEntityManager();$em->persist($product);$em->flush();return new Response('Created product id '.$product->getId());

}

事實上,Doctrine了解你所有的被管理的實體,當你調用flush()方法時,它會計算出所有的變化,并執行最有效的查詢可能。 比如,你要持久化總是為100的産品對象,然後調用flush()方法。Doctrine會建立一個唯一的預備語句并重複使用它插入。 這種模式成為Unit of work。

在建立和更新對象是,工作流是相同的。Doctrine提供了一個類庫允許你通過程式設計加載測試資料到你的項目。該類庫為DoctrineFixturesBundle(http://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html)

從資料庫中讀取對象

從資料庫中擷取對象更容易,舉個例子,加入你配置了一個路由來基于它的ID顯示特定的product。

public function showAction($id)

{$product = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product'))->find($id);if(!$product){throw $this->createNotFoundException('No product found for id ' .$id);

}//do something,想把$product對象傳遞給一個template等。

}

當你查詢某個特定的産品是,你總是需要使用它的"respository"。你可以認為Respository是一個PHP類,它的唯一工作就是幫助你從某個特定類哪裡擷取實體。你可以為一個實體對象通路一個repository對象,如下:

$repository = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product');

其中AcmeStoreBundle:Product是簡潔寫法,你可以在Doctrine中任意使用它來替代實體類的全限定名稱。

Acme\StoreBung\Entity\Product

你一旦有了Repository,你就可以通路其所有分類的幫助方法了。

//通過主鍵查詢(一般為"id")

$product=$repository->find($id);//動态方法名基于列值查找

$product=$repository->findOneById($id);$product=$repository->findOneByName('foo');//查詢所有産品

$products=$repository->findAall();//基于任意列值查找一組産品

$products = $repository->findByPrice(19.99);

你也可以發揮findBy和findOneBy方法的優勢很容易的基于多個條件來擷取對象。

//按照名字和價格來擷取一個比對的對象

$product=$repository->findOneBy(array('name'=>'foo','price'=>19.99));//查詢比對名字的所有産品并按照價格排序

$products = $repository->findBy(array('name'=> 'foo'),

array('price'=>'ASC')

);

更新對象

一旦你從Doctrine中擷取了一個對象,那麼更新它就變得很容易了。假設你有一個路由映射一個産品id到一個controller的更新行為。

public function updateAction($id)

{$em = $this->getDoctrine()->getEntityManager();$product = $em->getRepository('AcmeStoreBundle:Product')->find($id);if (!$product) {throw $this->createNotFoundException('No product found for id '.$id);

}$product->setName('New product name!');$em->flush();return $this->redirect($this->generateUrl('homepage'));

}

更新一個對象包括三步:

1.從Doctrine取出對象

2.修改對象

3.在實體管理者上調用flush()方法

注意調用 $em->persist($product) 在這裡沒有必要。我們回想一下,調用該方法的目的主要是告訴Doctrine來管理或者“watch"$product對象。

在這裡,因為你已經取到了$product對象了,說明已經被管理了。

删除對象:

删除一個對象,需要從實體管理者那裡調用remove()方法。

$em->remove($product);$em->flush();

正如你想的那樣,remove()方法告訴Doctrine你想從資料庫中移除指定的實體。真正的删除查詢沒有被真正的執行,直到flush()方法被調用。

查詢對象:

你已經看到了repository對象允許你執行一些基本的查詢而不需要你做任何的工作。

$repository->find($id);$repository->findOneByName('Foo');

當然,Doctrine 也允許你使用Doctrine Query Language(DQL)寫一些複雜的查詢,DQL類似于SQL,隻是它用于查詢一個或者多個實體類的對象,而SQL則是查詢一個資料庫表中的行。

在Doctrinez中查詢時,你有兩種選擇:寫純Doctrine查詢 或者 使用Doctrine的查詢建立器。

用DQL查詢對象:

假設你想查詢産品,需要傳回價格高于19.99的産品,并且要求按價格從低到高排列。我們可以在相應的Controller裡進行如下操作:

$em = $this->getDoctrine()->getEntityManager();$query = $em->createQuery('SELECT p FROM AcmeStoreBundle:Product p WHERE p.price > :price ORDER BY p.price ASC')->setParameter('price', '19.99');$products = $query->getResult();

如果你習慣了寫SQL,那麼對于DQL也應該不會感到陌生。它們之間最大的不同就是你需要思考對象,而不是資料庫表行。正因為如此,是以你從AcmeStoreBundle:Product選擇并給它定義别名p。getResult()方法傳回一個結果數組。如果你隻需要一個對象,你可以使用getSingleResult()方法。

$product = $query->getSingleResult();

如果沒有符合要求的結果,getSingleResult()方法會抛出一個 Doctrine\ORM\NoResultException 異常和如果不隻有一個結果傳回那麼就會

抛出一個Doctrine\ORM\NonUniqueResultException 異常。是以,如果你要使用該方法的話,需要把它包裹在一個try-catch塊内,以確定隻有

一個結果被傳回。

$query = $em->createQuery('SELECT ....')->setMaxResults(1);try{$product = $query->getSingleResult();

}catch (\Doctrine\Orm\NoResultException $e) {$product = null;

}//...

DQL的文法難以置信的強大,允許你很容易的倆和多個實體,分組等進行查詢。

設定參數:

注意setParameter()方法,在使用Doctrine時,把任何的外部值設定成占位符是一個非常好的做法。

比如上例中 ...WHERE p.price>:price ...

這樣你可以通過調用setParameter()方法為price占位符設定具體值。

->setParameter('price', '19.99')

使用參數而不是直接把具體在插入到查詢字元串中是為了放置SQL注入攻擊,是以必須始終這麼做。如果你使用了多個參數,你可以使用setParameters()方法一次性設定他們的值。

->setParameters(array('price'=>'19.99',

'name' =>'foo',))

使用Doctrine的查詢建立器

除了直接編寫查詢以外,你可以使用Doctrine的QueryBuilder來做相同的工作。面前對象接口。如果你使用IDE,你還可以擷取自動編譯檢查的好處。

$repository = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product');$query = $repository->createQueryBuilder('p')->where('p.price > :price')->setParameter('price', '19.99')->orderBy('p.price', 'ASC')->getQuery();$products = $query->getResult();

QueryBuilder對象包含了建立查詢的所有必須的方法。通過調用getQuery()方法,查詢建立器将傳回一個标準的Query對象。它跟我們直接寫查詢對象效果相同。

自定義Repository類

在上面你已經開始在controller中建立和使用負責的查詢了。為了隔離,比阿育測試和重用這些查詢,一個好的辦法是為你的實體建立一個自定義的repository類并添加相關邏輯查詢方法。要定義repository類,首先需要在你的映射定義中添加repository類的聲明:

在實體類中聲明方式:

//src/Acme/StoreBundle/Entity/Product.php

namespace Acme\StoreBundle\Entity;use Doctrine\ORM\Mapping asORM;

classProduct

{//...

}

YAML格式:

#src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml

Acme\StoreBundle\Entity\Product:type:entity

repositoryClass:Acme\StoreBundle\Repository\ProductRepository#...

XML格式:

然後通過運作跟之前生成丢失的getter和setter方法同樣的指令行,Doctrine會為你自動生成repository類。

$php app/console doctrine:generate:entities Acme

接下來,添加一個新方法findAllOrderedByName() 到新生成的repository類。該方法将查詢所有的Product實體,并按照字元順序排列。

//src/Acme/StoreBundle/Repository/ProductRepository.php

namespace Acme\StoreBundle\Repository;useDoctrine\ORM\EntityRepository;class ProductRepository extendsEntityRepository

{public functionfindAllOrderedByName()

{return $this->getEntityManager()->createQuery('SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC')->getResult();

}

}

注意在Repository類中可以通過$this->getEntityManager()方法類擷取實體管理者。如此一來你就可以像使用預設的方法一樣使用這個新定義的方法了:

$em = $this->getDoctrine()->getEntityManager();$products = $em->getRepository('AcmeStoreBundle:Product')->findAllOrderedByName();

在使用自定義的repository類時,你依然可以通路原有的預設查找方法,比如find() 和findAll()等。

實體關系/關聯

假設你應用程式中的産品屬于一确定的分類。這時你需要一個分類對象和一種把Product和Category對象聯系在一起的方式。首先我們建立Category實體,我們最終要通過Doctrine來對其進行持久化,是以我們這裡讓Doctrine來幫我們建立這個類。

$php app/console doctrine:generate:entity --entity="AcmeStoreBundle:Category" --fields="name:string(255)"

該指令行為你生成一個Category實體,包含id字段和name字段以及相關的getter和setter方法。

關系映射中繼資料:

聯系Category和Product兩個實體,首先在Category類中建立一個products屬性:

Category類中聲明格式:

//src/Acme/StoreBundle/Entity/Category.php

// ...

useDoctrine\Common\Collections\ArrayCollection;classCategory

{//...

protected $products;public function__construct()

{$this->products = newArrayCollection();

}

}

YAML定義格式:

#src/Acme/StoreBundle/Resources/config/doctrine/Category.orm.yml

Acme\StoreBundle\Entity\Category:type:entity#...

oneToMany:products:targetEntity:Product

mappedBy:category#不要忘記在實體的 __construct() 方法中初始化集合

首先,因為一個Category對象将關系到多個Product對象,一個products數組屬性被添加到Category類儲存Product對象。

其次,這裡沒有被做因為Doctrine需要它,但在應用程式中為每一個Category來儲存一個Product數組非常有用。

代碼中__construct()方法非常重要,因為Doctrine需要$products熟悉成為一個ArrayCollection對象,它跟數組非常類似。targetEntity 的值可以使用合法的命名空間引用任何實體,而不僅僅是定義在同一個類中的實體。 如果要關系一個定義在不同的類或者bundle中的實體則需要輸入完全的命名空間作為目标實體。

接下來,因為每個Product類可以關聯一個Category對象,所有添加一個$category屬性到Product類:

在Product類聲明中定義:

//src/Acme/StoreBundle/Entity/Product.php

// ...

classProduct

{//...

protected $category;

}

YAML定義格式:

#src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml

Acme\StoreBundle\Entity\Product:type:entity#...

manyToOne:category:targetEntity:Category

inversedBy:products

joinColumn:name:category_id

referencedColumnName: id

最後,到現在為止,我們添加了兩個新屬性到Category和Product類。現在告訴Doctrine來為它們生成getter和setter方法。

$php app/console doctrine:generate:entities Acme

我們先不看Doctrine的中繼資料,你現在有兩個類Category和Product,并且擁有一個一對多的關系。Category包含一個數組Product對象,Product包含一個Category對象。換句話說,你已經建立了你所需要的類了。

symfony mysql_Symfony2學習筆記之資料庫操作

現在讓我們來看看在Product類中為$category配置的中繼資料。它告訴Doctrine關系類是Category并且它需要儲存category的id到product表的category_id字段。換句話說,相關的分類對象将會被儲存到$category屬性中,但是在底層,Doctrine會通過存儲category的id值到product表的category_id列持久化它們的關系。Category類中$product屬性的中繼資料配置不是特别重要,它僅僅是告訴Doctrine去查找Product.category屬性來計算出關系映射是什麼。

在繼續下去之前,首先确定告訴Doctrine添加一個新的category表和product.category_id列以及新的外鍵。

$php app/console doctrine:schema:update --force

儲存關系實體:

現在讓我們來看看Controller内的代碼如何處理:

//...

useAcme\StoreBundle\Entity\Category;useAcme\StoreBundle\Entity\Product;useSymfony\Component\HttpFoundation\Response;//...

class DefaultController extendsController

{public functioncreateProductAction()

{$category = newCategory();$category->setName('Main Products');$product = newProduct();$product->setName('Foo');$product->setPrice(19.99);//relate this product to the category

$product->setCategory($category);$em = $this->getDoctrine()->getEntityManager();$em->persist($category);$em->persist($product);$em->flush();return newResponse('Created product id: '.$product->getId().' and category id: '.$category->getId()

);

}

}

現在,一個單獨的行被添加到category和product表中。新産品的product.categroy_id列被設定為新category表中的id的值。Doctrine會為你管理這些持久化關系。

擷取相關的對象:

當你需要擷取關聯的對象時,你的工作流暢跟以前一樣。首先擷取$product對象,然後通路它的關聯Category。

public function showAction($id)

{$product = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product')->find($id);$categoryName = $product->getCategory()->getName();//...

}

在這個例子中,你首先基于産品id查詢一個Product對象,接下來當你調用$product->getCategory()->getName() 時,Doctrine默默的為你執行了第二次查詢,查找一個與該産品相關的category,它生成一個$category對象傳回給你。

symfony mysql_Symfony2學習筆記之資料庫操作

重要的是你很容易的通路到了product的關聯對象category。但是category的資料并不會被取出來而直到你請求category的時候。這就是延遲加載。你也可以從其它方向進行查詢:

public function showProductAction($id)

{$category = $this->getDoctrine()->getRepository('AcmeStoreBundle:Category')->find($id);$products = $category->getProducts();//...

}

在這種情況下,同樣的事情發生了。你首先查查一個category對象,然後Doctrine制造了第二次查詢來擷取與之相關聯的Product對象們。隻有在你調用->getProducts()時才會執行一次。 $products變量是一個通過它的category_id的值跟給定的category對象相關聯的所有Product對象的集合。

關系和代理類:

延遲加載成為可能是因為Doctrine傳回一個代理對象來代替真正的對象:

$product = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product')->find($id);$category = $product->getCategory();//輸出結果 "Proxies\AcmeStoreBundleEntityCategoryProxy"

echo get_class($category);

該代理對象繼承了Category對象,從外表到行為都非常像category對象。通過這個代理對象,Doctrine可以延遲查詢真正的Category對象資料,直到真正需要它時(調用$category->getName())。Doctrine生成了代理對象并把它存儲到cache目錄中,盡管你可能從來沒有發現過它。記住它這一點很重要。

我們可以通過join連接配接來一次性取出product和category資料。這時Doctrine将會傳回真正的Category對象,因為不需要延遲加載。

連接配接相關記錄:

在之前的我們的查詢中,會産生兩次查詢操作,一次是擷取原對象,一次是擷取關聯對象。當然,如果你想一次通路兩個對象,你可以通過一個join連接配接來避免二次查詢。把下面的方法添加到ProductRepository類中:

//src/Acme/StoreBundle/Repository/ProductRepository.php

public function findOneByIdJoinedToCategory($id)

{$query = $this->getEntityManager()->createQuery('SELECT p, c FROM AcmeStoreBundle:Product p

JOIN p.category c

WHERE p.id = :id')->setParameter('id', $id);try{return $query->getSingleResult();

}catch (\Doctrine\ORM\NoResultException $e) {return null;

}

}

現在你就可以在你的controller中一次性查詢一個産品對象和它關聯的category對象資訊了。

public function showAction($id)

{$product = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product')->findOneByIdJoinedToCategory($id);$category = $product->getCategory();//...

}

生命周期回調:

有時候你可能需要在一個實體被建立,更新或者删除的前後執行一些行為。因為它們回調的方法處在一個實體不同的生命周期階段,是以這些行為被稱為"生命周期回調“。如果你用聲明中繼資料方式,開啟一個生命周期回調,需要如下設定:

classProduct

{//...

}

如果你選擇YAML或者XML格式為你定義映射,則不需要它。現在你可以告訴Doctrine在任何可用的生命周期事件上來執行一個方法了。比如,假設你想在一個新的實體第一次被建立時設定設定建立日期列(created)為目前日期。

聲明式定義:

public functionsetCreatedValue()

{$this->created = new\DateTime();

}

YAML格式定義:

#src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml

Acme\StoreBundle\Entity\Product:type:entity#...

lifecycleCallbacks:prePersist: [ setCreatedValue ]

XML格式定義:

現在在實體第一次被儲存時,Doctrine會自動調用這個方法使created日期自動設定為目前日期。還有其它生命周期事件可用:

preRemove

postRemove

prePersist

postPersist

preUpdate

postUpdate

postLoad

loadClassMetadata

生命周期回調和事件監聽:

注意到setCreatedValue()方法不需要接收任何參數。這是生命周期回調通常的做法和慣例。生命周期回調應該方法簡單,更關注于實體内部傳輸資料。比如設定一個建立/更新字段,生成一個定量值等。如果你需要一些比較大的行為活動,像執行日志或者發送郵件,你應該注冊一個擴充類作為事件監聽器或接收器給它賦予通路所需資源的權利。

Doctrine擴充:Timestampable, Sluggable

Doctrine非常靈活,許多第三方擴充可以使用,讓你很容易在你的實體上執行一些重複和通用的任務。包括Sluggable,Timestampable,Loggable,Translatable 和 Tree。

Doctrine字段類型參考:

Doctrine配備了大量可用的字段類型。它們每一個都能映射PHP資料類型到特定的列類型,無論你使用什麼資料庫。下面是Doctrine支援的資料類型:

字元串:

string 短字元串

text 大型字元串

數字:

integer

smallint

bigint

decimal

float

日期和時間:

date

time

datetime

其它類型:

boolean

object(序列化并存儲到CLOB字段)

array(序列化并存儲到CLOB字段)

可選字段:

每個字段都有一些可選項。包括type(預設string),name,length,unique 和nullable。

比如:

protected $name;

protected $email;

YAML格式:

fields:

#字元串長度為 255 不能為空l

#(影響預設值的 "length" 和 *nullable* 可選)

#type 屬性在yml中是必須定義的

name:type: string

#字元串長度為150持久化一個 "email_address" 列

#并有一個唯一索引.

email:type: stringcolumn:email_address

length: 150unique: true

控制台指令:

Doctrine2 ORM繼承官方的多個控制台指令在doctrine命名空間下。你可以通過如下指令檢視:

$php app/console

一個可用的指令行清單将會被列印出來。有許多是以doctrine:開頭的。你可通過運作help指令來檢視它們的詳細,比如,檢視doctrine:database:create 任務,則需要運作:

$php app/console help doctrine:database:create

另外一些可用的有趣的指令行任務包括:

doctrine:ensure-production-settings 用來檢視目前還将配置是否對産品有效。這個一般在prod環境下運作:

$php app/console doctrine:ensure-production-settings --env=prod

doctrine:mapping:import 允許Doctrine自己檢查一個已有的資料庫并建立映射資訊。

doctrine:query:dql 和 doctrine:query:sql 允許你直接在指令行執行DQL或者SQL查詢。

總結思考:

有了Doctrine,你可以集中精力到你的對象以及怎樣把它應用于你的應用程式中,而不必擔心資料庫持久化。因為Doctrine允許你使用任何的PHP對象儲存你的資料并依靠映射中繼資料資訊來聯系一個對象到特定的資料庫表。

盡管Doctrine圍繞着一個簡單的概念發展而來,但是它不可思議的強大。允許你建立複雜的查詢和訂閱事件,通過訂閱事件你可以在整個持久化過程中執行一些不同的行為。