CodeIgniter 下引入ORM Doctrine

作了兩年的CI開發,一直使用activeRecord來操做數據庫。簡單,輕巧加方便。最近一個項目交給手下去作,也是採用從數據庫設計入手的開發流程,如今已經上線運行。經歷了理清需求,設計數據庫,在CI中創建model, controller,需求變動,更改數據庫,更改代碼,增長需求,更改數據庫等過程。回頭來看,當須要瞭解全局代碼和業務邏輯需求時,仍是得從數據庫入手,忽然有一種厭煩的感腳:對象的屬性都在數據庫裏,而相關的操做在代碼中,以爲很分裂。回想多年前開發的C#與JAVA中都有一些好用的ORM的框架,對我來講,ORM最大的好處是隱藏數據庫,項目前期設計時根據需求來設計對象,輕裝上陣,沒必要早早地陷入增改刪查中;直接利用工具將對象映射到數據庫中;數據庫的增改刪查也都是面向對象的。php

可能存在的兩點顧慮:html

  1. 既然要由對象自動映射到數據庫,天然要遵照一套metaData規則才行。
  2. 性能問題,由ORM自動生成sql語句,性能可能不如之前。但對比框架的可讀性/可維護性與少量的硬件性能成本,仍是選擇框架優先。另外,相信ORM的90%的性能影響不大,少量的實在ORM解決不了的問題也能提供原生的sql來解決,整體來講,是利大於弊。

(官方參考文檔:http://doctrine-orm.readthedocs.org/en/latest/tutorials/getting-started.htmlmysql

開始吧,咱們的目的是什麼,沒有蛀牙!好吧,這只是咱們的一個目的,還在其它的目的:sql

  • 根據創建的對象生成數據庫;
  • 新增對象持久化到數據庫中;
  • 能使用entity來方便查詢數據裏的信息並達到更改。

1. 在CI下安裝doctrine

     a. 最新的CI 3.0已支持composer。在application文件夾下創建composer.son文件以下。(不是在CI根目錄下)。 注意autoload參數(不是官方例子中的/src/文件夾) 數據庫

          

{
    "require": {
        "doctrine/orm": "2.4.*",
        "symfony/yaml": "2.*"
    },
    "autoload": {
        "psr-0": {"": "models/entities"}
    }
}

 

notes: 上面autoload參數很重要,由於doctrine的啓動須要指明entity目錄,原始例子中給定的是/src,這裏咱們放在CI的model/entities目錄下,另外,同時建立model/generated 與 models/proxies目錄,generated目錄用來由數據庫生成entity,proxies目錄用來存放lazy load須要生成的代碼.bootstrap

     b. 安裝doctrine: composer install. 安裝後目錄結構以下:app

      

2. 配置bootstrap與cli-config

在doctrine中,bootstrap負責建立entityManager,entityManager是整個doctrine對外提供的操做接口: 隱藏數據庫接口,提供了對entity的查詢,更新及持久化。composer

在bootstrap中,首先使用composer自帶的功能對整個doctrine實現加載。(這裏保留了composer功能,實現將doctrine引入到CI修改最小化)框架

建立基本的entityManager只須要兩步:數據庫設計

  1. 使用setup建立config。
  2. 初始化數據庫配置對象。

使用數據庫鏈接對象建立entityManager後咱們可能及不可耐就想用來從對象來逆向工程數據庫了。別急,慢慢來。

 

<?php
// bootstrap.php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\ClassLoader,
    Doctrine\DBAL\Logging\EchoSQLLogger,
    Doctrine\Common\Cache\ArrayCache;

date_default_timezone_set("Asia/Shanghai");

require_once "vendor/autoload.php";

// database configuration parameters
if(defined(APPPATH))
{
    require_once APPPATH.'config/database.php';
    $conn = array(
            'driver' => 'pdo_mysql',
            'user' =>     $db['default']['username'],
            'password' => $db['default']['password'],
            'host' =>     $db['default']['hostname'],
            'dbname' =>   $db['default']['database']
        );
}
else
{
    $conn = array(
    'driver' => 'pdo_mysql',
    'user' =>     'root',
    'password' => '',
    'host' =>     '127.0.0.1',
    'dbname' =>   'doctrine'
);
}
//Below can be exected in cli
/*
require_once APPPATH.'vendor/Doctrine/Common/lib/doctrine/common/ClassLoader.php';
$doctrineClassLoader = new ClassLoader('Doctrine',  APPPATH.'libraries');
$doctrineClassLoader->register();
$entitiesClassLoader = new ClassLoader('models', rtrim(APPPATH, "/" ));
$entitiesClassLoader->register();
$proxiesClassLoader = new ClassLoader('Proxies', APPPATH.'models/proxies');
$proxiesClassLoader->register();
*/

// Create a simple "default" Doctrine ORM configuration for Annotations
$isDevMode = true;
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/models/entities"), $isDevMode);
// or if you prefer yaml or XML
//$config = Setup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode);
//$config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode);

$cache = new ArrayCache;
$config->setMetadataCacheImpl($cache);
$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__.'/models/entities'));
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCacheImpl($cache);

$config->setQueryCacheImpl($cache);

// Proxy configuration
$config->setProxyDir(__DIR__.'/models/proxies');
$config->setProxyNamespace('Proxies');

// Set up logger
//$logger = new EchoSQLLogger;
//$config->setSQLLogger($logger);
$config->setAutoGenerateProxyClasses( TRUE );

// obtaining the entity manager
global $entityManager;
$entityManager = EntityManager::create($conn, $config);
View Code

 

要讓entityManager知道用哪裏的對象來進行反向工程,下面這句就尤其重要了:

$config = SetupcreateAnnotationMetadataConfiguration(array(DIR."/models/entities"), $isDevMode);

(在這裏也提一下,當從數據庫生成entity時固然也要指明entity要放在哪一個文件夾了,使用的是EntityGenerator對象,使用該對象的generate方法時指定存放的文件夾就能夠了。)

官方文檔中使用的是命令行的方法來進行反向工程的,咱們這裏也依樣畫葫蘆,接下來建立必要的cli-config文件。這個文件相對來說就沒有bootstrap那麼長了,總公只有下面兩行便可:

 

requireonce "bootstrap.php";

return DoctrineORMToolsConsoleConsoleRunnercreateHelperSet($entityManager);

 

反向工程使用vendor/bin/中的doctrine命令:

 

vendor/bin/doctrine

 

其中經常使用的有以下:

 

vendor/bin/doctrine orm:schema-tool:create

vendor/bin/doctrine orm:schema-tool:update --force

 

notes: 使用update命令新增字段不會影響原先的數據。

 

好吧,是否是急不可奈要試一試了,輸入第一條create命令,咦,很差出現一個錯誤 「No Metadata Classes to process.」 ,心跳加快,冷靜,這是正常的,是由於咱們還沒創建咱們想要的entity呢。

創建entity進行反向工程

     1. 在/models/entities中創建咱們第一個entity: Product.php

          注意這裏的每個屬性都protected屬性,對應都有一對mutator(getter與setter)這是有什麼用處的呢?由官方文檔所說是用來方便doctrine來產生entity,而不是使用entity.field=foo的方式。具體在doctrine如何操做的有待進一步探索。對於主鍵Id是沒有setter方法的,你懂的。

     2. 如今咱們只是定義了對象,但數據庫構造是須要一些數據庫屬性的,類名與屬性前面的metadata就是來幹這個的。(定義的表名,對象屬性對應的數據庫字段名與字段屬性)

 

<?php
// src/Product.php
/**
 * @Entity @Table(name="products")
 **/
class Product
{
    /** @Id @Column(type="integer") @GeneratedValue **/
    protected $id;
    
    /** @Column(type="string") **/
    protected $name;


    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }
}

 

     3. 下面咱們就能夠使用下面命令來進行反向工程了,是否是很興奮!

          

vendor/bin/doctrine orm:schema-tool:update --force --dump-sql

 

     4. 下面咱們就來創建一段腳原本生成一個product並將其插入數據(持久化),你就會發現如何面向對象,隱藏數據庫操做的了。

  1. <?php 
    require_once "bootstrap.php";
    
    $newProductName = $argv[1];
    
    $product = new Product();
    $product->setName($newProductName);
    
    $entityManager->persist($product);
    $entityManager->flush();
    
    echo "Created Product with ID " . $product->getId() . "\n";

     5. 下面咱們就要使用cli來運行這段php腳本調用ORM框架來插入product了。

  1. $ php createproduct.php ORM 
    $ php createproduct.php DBAL

查看數據庫,是否是發現了新的數據已經插入了,ok大功告成。

相關文章
相關標籤/搜索