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:

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

报告相同问题?

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效