doujia5863 2017-02-10 10:02
浏览 56
已采纳

PHP MVC模型关系 - MySQL

I'm building a small and simple PHP content management system and have chosen to adopt an MVC design pattern.

I'm struggling to grasp how my models should work in conjunction with the database.

I'd like to separate the database queries themselves, so that if we choose to change our database engine in the future, it is easy to do so.

As a basic concept, would the below proposed solution work, is there a better way of doing things what are the pitfalls with such an approach?

First, I'd have a database class to handle all MySQL specific pieces of code:

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);
    }
}

Second, I'd have a model, in this case to hold all my menu items:

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'];
    }
}

Finally, I'd have a 'factory' to pull the two together:

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;
    }
}
  • 写回答

1条回答 默认 最新

  • douyi9787 2017-02-10 12:05
    关注

    Your solution will work of course, but there are some flaws.

    1. Class Database uses inside it's constructor class DatabaseFactory - it is not good. DatabaseFactory must create Database object by itself. However it okay here, because if we will look at class Database, we will see that is not a database, it is some kind of QueryObject pattern (see link for more details). So we can solve the problem here by just renaming class Database to a more suitable name.

    2. Class MenuItemModelFactory is extending class Database - it is not good. Because we decided already, that Database is just a query object. So it must hold only methods for general querying database. And here you mixing knowledge of creating model with general database querying. Don't use inheritance. Just use instance of Database (query object) inside MenuItemModelFactory to query database. So now, you can change only instance of "Database", if you will decide to migrate to another database and will change SQL syntax. And class MenuItemModelFactory won't change because of migrating to a new relational database.

    3. MenuItemModelFactory is not suitable naming, because factory purpose in DDD (domain-driven design) is to hide complexity of creating entities or aggregates, when they need many parameters or other objects. But here you are not hiding complexity of creating object. You don't even "creating" object, you are "loading" object from some collection.

    So if we take into account all the shortcomings and correct them, we will come to this design:

    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;
        }
    }
    

    Also consider reading this:

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 R语言卸载之后无法重装,显示电脑存在下载某些较大二进制文件行为,怎么办
  • ¥15 java 的protected权限 ,问题在注释里