2012-03-30 58 views
2

我正在爲我公司購買的數據倉庫寫一個Web報表擴展。數據倉庫是數據模型中立的,並且具有存儲表格關係和字段的元層數據的表格。這讓我很容易編寫一個基本的ORM類,這正是我想要做的。這一切都有效,但...手滾ORM類 - 單身,靜態父,?

我的ORM類包含PDO實例,表的字段(用作白名單)以及字段的元層信息。它還具有映射表關係的便利函數(生成FROM/JOIN子句)並映射Web提供的過濾器(生成WHERE子句)。

SELECT子句根據請求的模型在ORM的子類中生成。當頁面加載時,需要建立幾個模型。很顯然,我只需要ORM的一個實例(像monostate),但是我希望每個子類都繼承ORM的屬性和便利功能,而不必在每次實例化子類時都重做父類的查詢。

單身模式可能適合在這裏,但我發現很難繼承一個單身人士。而我似乎無法讓靜態屬性正常工作。

我覺得我很接近,但我要麼失去了某些東西,要麼讓它變得困難。我現在正在考慮將這些屬性放入一個細小的類中,並從那裏延伸,同時將便利功能與特性混合在一起。我已經看到了這個話題的類似問題,但還沒有提出明確的解決方案。

我不在工作,但這是一個簡單的代碼示例,應該給你我要做的事情的要點。

Class ORM { 

    protected $conn; 
    protected $fields; 
    protected $relations; 
    protected $table; 
    protected $sql; 

    public function __construct ($view, $database) { 

     $this->conn = new PDO(...$database...); 
     $this->table = $view; 
     $this->getFields(); 
     $this->getRelations(); 
    } 

    private function getFields() { 
     //select fields from metalayer where table = $table; 
     //$this->fields = $result; 
    } 

    private function getRelations() { 
     //select relations from relations where table = $table; 
     //$this->relations = $result; 
    } 

    protected function mapTables ($tables) { 
     // $this->sql = "FROM $this->table"; 
     // foreach ($tables as $table) { 
     // $this->sql .= "LEFT JOIN $table ON $relations[$table]['key1'] = $relations[$table]['key2']; 
    } 

    protected function mapFilters ($filters) { 
     // $this->sql = "WHERE 1=1"; 
     // foreach $filters as $filter { 
     // $this->sql .= "AND ($filter['field'] = $filter['criterion1'] OR ...criterion2, etc.) 
    } 
} 

Class ExampleModelDAO extends ORM { 
    public function __construct($view, $database, $params) { 
     parent::__construct($view, $database); 
     // parse params 
     parent::mapTables($tables); 
     parent::mapFilters($filters); 
    } 

    public function get() { 
     // Prepend $this->sql with SELECT statement specific to model 
     // Query database and return model 
    } 
} 
+0

您應該將PDO實例作爲依賴項傳遞。這樣做會讓你在測試時更容易替換模擬對象。 – Xeoncross 2012-03-30 02:32:11

回答

2

首先,你的orm/model應該不知道關於數據庫的任何信息。有一百萬種方法可以做到這一點,但我會從一個簡單的數據庫類開始,它提供了一些在pdo之上的附加功能,但是完全獨立於其他任何東西。這也將允許您直接訪問數據庫,而不需要模型,也不需要創建與數據庫無關的模型。爲了獲得最大的靈活性,您需要查看適配器模式和數據映射器。但是,爲了簡單起見,下面是將模型映射到數據存儲的一個非常基本的示例(沒有適配器或數據映射器)。

<?php 
class DB extends PDO { 
    public function __construct() { 
     try { 
      parent::__construct(/* db info */); 
     } catch (Exception $e) { 
      // handle the error 
     } 
    } 

    public function read() { 
     // read from database 
    } 

    public function write() { 
     // write to database 
    } 

    // etc... 
} 

因此,你的數據庫類將有一些簡單的crud操作。然後你的orm可以像這樣與這個類交互...

<?php 
class ORM { 
    public function __construct() { 
     $this->db = new DB(); 
    } 

    public function find($options) { 
     return $this->db->read($options); 
    } 

    public function save($data) { 
     return $this->db->create($data); // or update() 
    } 

    // etc... 
} 

這應該足以讓你走了。此外,而不是使用單件模式爲你的數據庫,如果你不管理你的連接外,你可以使用一個簡單的修改後的註冊表型模式(注意,這是不是一個真正的註冊表)

<?php 

class DB extends PDO { 
    protected static $instances = array(); 

    public function __construct() ... 

    public static function get($name) { 
     if(! isset(self::$instances[$name]) { 
      self::$instances[$name] = new self(); 
     } 
     return self::$instances[$name]; 
    } 
} 

class ORM { 
    public function __construct() { 
     $this->db = DB::get('connection1'); 
    } 
} 

有更好的方法來做到這一點,但我會留給你。

+0

作爲一個附註,ORM *應該知道數據庫 - 畢竟這是一個** Object-relational-Mapper **。它知道如何向開發人員呈現對象模型,並將其轉換爲另一側的RDBMS調用。它是*模型*,不需要知道數據庫。 – Xeoncross 2012-03-30 02:31:13

+1

感謝您的意見,但我不同意。如果你的數據層被正確抽象了,那麼你的orm可以寫入數據庫,會話,緩存,日誌等等,不知道它寫入的對象是什麼。 – Rob 2012-03-30 02:54:31