2017-02-10 125 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; 
    } 
} 

还要考虑阅读本: