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 对于这个问题的解释说明
  • ¥200 询问:python实现大地主题正反算的程序设计,有偿
  • ¥15 smptlib使用465端口发送邮件失败
  • ¥200 总是报错,能帮助用python实现程序实现高斯正反算吗?有偿
  • ¥15 对于squad数据集的基于bert模型的微调
  • ¥15 为什么我运行这个网络会出现以下报错?CRNN神经网络
  • ¥20 steam下载游戏占用内存
  • ¥15 CST保存项目时失败
  • ¥15 树莓派5怎么用camera module 3啊
  • ¥20 java在应用程序里获取不到扬声器设备