2017-02-10 118 views
0

我正在構建一個小而簡單的PHP內容管理系統,並選擇採用MVC設計模式。PHP MVC模型關係 - MySQL

我很努力地掌握我的模型應該如何與數據庫結合使用。

我想分開數據庫查詢本身,所以如果我們選擇在將來更改數據庫引擎,很容易這樣做。

作爲一個基本的概念,下面提出的解決方案是否有效,是否有更好的方法來處理這種方法有什麼缺陷?

首先,我有一個數據庫類來處理的代碼,所有MySQL的某些片段:

class Database 
{ 
    protected $table_name; 
    protected $primary_key; 

    private $db; 

    public function __construct() 
    { 
     $this->db = DatabaseFactory::getFactory()->getConnection(); 
    } 

    public function query($sql) 
    { 
     $query = $this->db->prepare($sql); 
     $query->execute(); 
     return $query->fetchAll(); 
    } 

    public function loadSingle($id) 
    { 
     $sql = "SELECT * FROM $this->table_name WHERE $this->primary_key = $id"; 
     return $this->query($sql); 
    } 

    public function loadAll() 
    { 
     $sql = "SELECT * FROM $this->table_name"; 
     return $this->query($sql); 
    } 
} 

其次,我有一個模型,在這種情況下握住我的所有菜單項:

class MenuItemModel 
{ 
    public $menu_name; 
    public $menu_url;  

    private $data; 

    public function __construct($data) 
    { 
     $this->data = $data; 
     $this->menu_name = $data['menu_name']; 
     $this->menu_url = $data['menu_url']; 
    } 
} 

最後,我想有一個「工廠」拉兩個在一起:

class MenuItemModelFactory extends Database 
{ 
    public function __construct() { 
     $this->table_name = 'menus'; 
     $this->primary_key = 'menu_id'; 
     parent::__construct(); 
    } 

    public function loadById($id) 
    { 
     $data = parent::loadSingle($this->table_name, $this->primary_key, $id); 
     return new MenuItemModel($data); 
    } 

    public function loadAll() 
    { 
     $list = array(); 
     $data = parent::loadAll(); 
     foreach ($data as $row) { 
      $list[] = new MenuItemModel($row); 
     } 
     return $list; 
    } 
} 
+0

看看[存儲庫模式](http://stackoverflow.com/questions/16176990/proper-repository-pattern-design-in-php) – thodic

回答

0

您的解決方案將工作過程中,但有一些缺陷。

  1. Database它的構造函數類DatabaseFactory內使用 - 這是不好的。 DatabaseFactory必須自己創建Database對象。然而,這裏沒關係,因爲如果我們看類Database,我們會看到這不是數據庫,它是某種QueryObject模式(有關更多詳細信息,請參閱link)。所以我們可以通過將類別Database重命名爲更合適的名稱來解決問題。

  2. MenuItemModelFactory正在擴展類Database - 它不好。因爲我們已經決定,Database只是一個查詢對象。所以它只能保存通用查詢數據庫的方法。在這裏,您將創建模型的知識與通用數據庫查詢混合在一起。不要使用繼承。只需使用MenuItemModelFactory內的Database(查詢對象)實例來查詢數據庫。因此,現在,如果您決定遷移到另一個數據庫並更改SQL語法,則只能更改「數據庫」實例。而MenuItemModelFactory類不會因爲遷移到新的關係數據庫而改變。

  3. MenuItemModelFactory不適合命名,因爲DDD(域驅動設計)中的工廠目的是爲了隱藏創建實體或聚合的複雜性,當它們需要許多參數或其他對象時。但是在這裏你並沒有隱藏創建對象的複雜性。你甚至不「創建」對象,你是從某個集合中「加載」對象。

所以,如果我們考慮到所有的缺點,並加以改正,我們會得出這樣的設計:

class Query 
{ 
    protected $table_name; 
    protected $primary_key; 

    private $db; 

    public function __construct() 
    { 
     $this->db = DatabaseFactory::getFactory()->getConnection(); 
    } 

    public function query($sql) 
    { 
     $query = $this->db->prepare($sql); 
     $query->execute(); 
     return $query->fetchAll(); 
    } 

    public function loadSingle($id) 
    { 
     $sql = "SELECT * FROM $this->table_name WHERE $this->primary_key = $id"; 
     return $this->query($sql); 
    } 

    public function loadAll() 
    { 
     $sql = "SELECT * FROM $this->table_name"; 
     return $this->query($sql); 
    } 
} 

class MenuItemModel 
{ 
    public $menu_name; 
    public $menu_url;  

    private $data; 

    public function __construct($data) 
    { 
     $this->data = $data; 
     $this->menu_name = $data['menu_name']; 
     $this->menu_url = $data['menu_url']; 
    } 
} 

class MenuItemModelDataMapper 
{ 
    public function __construct() { 
     $this->table_name = 'menus'; 
     $this->primary_key = 'menu_id'; 
     $this->query = new Query(); 
    } 

    public function loadById($id) 
    { 
     $data = $this->query->loadSingle($this->table_name, $this->primary_key, $id); 
     return new MenuItemModel($data); 
    } 

    public function loadAll() 
    { 
     $list = array(); 
     $data = $this->query->loadAll(); 
     foreach ($data as $row) { 
      $list[] = new MenuItemModel($row); 
     } 
     return $list; 
    } 
} 

還要考慮閱讀本: