【问题标题】:CodeIgniter - Best Model ApproachCodeIgniter - 最佳模型方法
【发布时间】:2017-10-26 04:36:08
【问题描述】:

这已经困扰了我很长一段时间了。

据我所知,控制器是我进行验证、模型调用和数据显示的地方。而在只有一个目的的模型上,是我进行 SQL 查询的地方。

但是模型的最佳方法是什么?我是否必须使用不同的条件/方法创建很多函数,或者我必须在一个函数中完成所有这些,专门用于我数据库中的单个表。以下面的代码为例:

多功能:

class Sword_model extends CI_Model {

    public function __construct()
    {
        $this->load->database();
        $this->load->library('session');
        $this->load->helper('url_helper');
    }

    public function getsword($swordid = NULL)
    {
        if($swordid === NULL){
            $query = $this->db->query("SELECT * FROM sword_tb");
            return $query->result_array();
        }

        $query = $this->db->query("SELECT * FROM sword_tb WHERE sword_id = ?", array($swordid));
        return $query->row_array();
    }

    public function getstrongswords($strong = NULL)
    {

        if($strong === NULL){
            return false;
        }

        $query = $this->db->query("SELECT * FROM sword_tb WHERE strong = ?", array($strong));
        return $query->result_array();

    }

    /*** AND MORE SUCCEEDING FUNCTIONS BELOW FOR DIFFERENT COLUMNS/CONDITIONS ***/
}

优点:这很简单,更容易理解(我认为更快)
缺点:您必须为不同的条件/列手动创建函数


单一功能:

class Sword_model extends CI_Model {

    public function __construct()
    {
        $this->load->database();
        $this->load->library('session');
        $this->load->helper('url_helper');
    }

    public function getsword($column = NULL, $value = NULL, $condition = 'AND')
    {

        $query = 'SELECT * FROM sword_tb';
        $count = count($column);
        for($x = 0; $x < $count; $x++){
            if($x > 0){
                $query .= ' '.$condition;
            } else {
                $query .= ' WHERE (';
            }
            $query .= ' '.$column[$x].' = ?';
        }
        $query .= ' ORDER BY sword_name';

        $query = $this->db->query($query, $value);
        return $query->result_array();

    }

}

使用这种单函数方法,您可以通过将数组作为参数来调用该函数,如下所示:

$this->Sword_model->getsword(array('sword', 'strong'), array(3, 1), 'OR');

查询将如下所示:

SELECT * FROM sword WHERE (sword = ? OR strong = ?) ORDER BY sword_name

如果您将其留空,查询将如下所示:

SELECT * FROM sword ORDER BY sword_name

优点: 灵活
缺点: 比第一种方法慢(?)

两者之间更理想的是什么?或者还有其他更理想的方式吗?

【问题讨论】:

  • 作为 CI 用户,我建议使用像 db-&gt;getdb-&gt;query 这样的直接访问。这两者都工作得更快。 CI 也是整个 PHP 框架中的可定制框架。如果您需要更好的模型,您可以使用第三方模型或框架,例如 LARAVEL、Symfony
  • 大多数时候我使用db-&gt;get 来选择数据或做任何事情。但是db-&gt;query 是用于巨大查询(更多+1 连接)的最佳选择
  • @Logan Wayne,你的 cmets 你有答案吗?

标签: php codeigniter


【解决方案1】:

我更喜欢让每个表都有自己的模型,并采用不同的首选方法,就像您在“多模型”中所做的那样。这样,它更易于维护,更容易接近和理解代码。第二个是虽然它更难接近,但它可能并非在所有情况下都有用。

我使用 Codeigniter MVC 和 HMVC 已经 2 年多了。到目前为止,第一个是我的选择,它可以帮助我检查和维护我的代码,也有助于我未来的更新/代码。

【讨论】:

    【解决方案2】:

    你可以试试 ORM(对象关系映射)

    Datamapper 是一个 ORM 库。它旨在将您的数据库表映射为易于使用的对象。

    Datamapper安装成功后

    如果您有一个名为 users 的表

    创建一个名为user的模型

    <?php
    
    class User extends DataMapper {
    
        function __construct($id = NULL)
        {
            parent::__construct($id);
        }
    }
    

    在您的控制器中,您可以简单地通过

    访问数据
        $u = new user(); // Singular of model name is required
        $u->get();
    
        foreach ($u as $user => $value) 
        {
            echo $user->name;
        }
    

    通过这种方法,您必须为表创建每个模型并通过控制器访问数据

    【讨论】:

      【解决方案3】:

      我更喜欢一个通用模型,使用它我可以执行所有 mysql 查询(这不是那么复杂,否则如果需要一些过于复杂的查询,您需要编写一个查询字符串并在少数情况下执行它。 ) 否则,您可以通过传递数据数组和表名从控制器调用模型的通用函数,其余部分将由模型管理。 这是我使用的通用模型:

      <?php
      
      /*
        All user module related databse functions
        Author : Himanshu Upadhyay (himanshuvarun@gmail.com)
       */
      
      if (!defined('BASEPATH'))
          exit('No direct script access allowed');
      
      class User_Model extends MY_Model {
      
          public function __construct() {
              parent::__construct();
          }
      
          public function get_rows($filters = array(), $table = TBL_USER) {
              return parent::get_rows($filters, $table);
          }
      
          public function get_columns($table = TBL_USER) {
              return parent::get_columns($table);
          }
      
          public function update_table($data, $where, $table = TBL_USER, $set = '') {
              return parent::update_table($data, $where, $table, $set = '');
          }
      
          public function get_count($filters = array(), $table = TBL_USER) {
              return parent::get_count($filters, $table);
          }
      
          public function insert($data, $table = TBL_USER) {
              return parent::insert($data, $table);
          }
      
          public function delete($where, $table = TBL_USER) {
              return parent::delete($where, $table);
          }
      /* End of file user_model.php */
      /* Location: ./application/models/user_model.php */
      ?>
      

      在你的控制器中,你可以像这样调用模型函数:

      $user_data['first_name'] = 'ABC';
      $user_data['last_name'] = 'XYZ';
      $this->user_model->insert($user_data, 'tbl_users');  // This is calling `insert` function of user model with first array argument with the data with column names as keys of the array and 2nd argument is the table name.
      

      结论:所以通过这种方法,您可以在所有控制器中加载user_model,并且您可以在所有控制器中使用它的所有通用函数。因此,这种方法避免了获取、插入和更新数据的冗余模型函数,并通过为每个表定义不同的模型来节省我们的时间。

      【讨论】:

        【解决方案4】:

        大多数时候,多个函数更容易调试、理解和维护。

        也就是说,您可以减少多方法模型代码的重复性。 考虑以下。 (__construct() 没有显示,因为你的很好。)

        class Sword_model extends CI_Model
        {
            protected $get_all_sql = 'SELECT * FROM sword_tb';
            protected $get_where_sql = "SELECT * FROM sword_tb WHERE sword_id = ?";
        
            public function getsword($swordid = NULL)
            {
                $sql = isset($swordid) ? $this->get_where_sql : $this->get_all_sql;
                $bind = isset($swordid) ? $swordid : FALSE;
                return $this->do_Query($sql, $bind);
            }
        
            public function getstrongswords($strong = NULL)
            {
                if(isset($strong))
                {
                    return $this->do_Query($this->get_where_sql, $strong);
                }
                //Returning an empty array means the controller can skip doing a conditional 
                //check for a model return === FALSE.
                //foreach() won't choke on an empty array, but it will choke if passed FALSE
                return array();
            }
        
            protected function do_Query($sql, $binds = FALSE)
            {
                $query = $this->db->query($sql, $binds);
                return $query->result_array();
            }
        }
        

        但是,“灵活”的方法在某些情况下可能很有用。

        “单人”与“灵活”之间的速度差异可以忽略不计,无需考虑。需要考虑的是,当您尝试响应更多“条件”时,“灵活”很快就会变得笨拙。

        有些东西可以让编写“灵活”的模型方法变得更容易——更容易编写、理解、调试和维护。不要手动构造查询字符串并将它们传递给$this-&gt;db-&gt;query(),而是使用Query Builder。它专为需要有条件地构建查询语句的情况而设计。

        getsword() 的“灵活”版本至少有一个限制,那就是您不能选择不属于 WHERE 子句的列。

        在此处使用查询构建器是一种实现灵活方法的方法,该方法为 AND WHERE 和 OR WHERE 子句构建查询。希望该方法之前的 DocBlock 能够提供一些见解。

        class Sword_model extends CI_Model
        {
            protected $get_all_sql = 'SELECT * FROM sword_tb';
            protected $get_where_sql = "SELECT * FROM sword_tb WHERE sword_id = ?";
        
            /**
             * 
             * @param mixed $columns The columns to retrieve. Can be either a string 
             * e.g. 'title, content, date',
             * or it can be an array e.g. array('title', 'content', 'date') 
             * 
             * @param array $where If provided, must be an associative array where 
             * the key => value is 'field_name' => value_to_match, e.g. 
             * array('title' => "Kill Bill") 
             * $where requires a different structure when the $condition argument is 
             * "OR". In this case the value part should provide multiple values. 
             * These values can be provided either in an array 
             * or a comma separated string list. For instance:
             *    As an array, $where = array('field_name' => array('val1', 'val2'));
        
             *    As a string, $where = array('field_name' => 'val1, val2'));
             * 
             * @param string $condition For this example can be either 'AND' (default) or 'OR'
             */
            public function getsword($columns = NULL, $where = NULL, $condition = 'AND')
            {
                if(!empty($columns)) //No $columns means SELECT *
                {
                    $this->db->select($columns);
                }
        
                $condition = strtoupper($condition); //Don't assume
                if(!empty($where))
                {
                    if($condition === 'OR')
                    {
                        foreach($where as $key => $values)
                        {
                            if(is_string($values))
                            {
                                $values = explode(', ', $values);
                            }
                            if(is_array($values))
                            {
                                foreach($values as $matching)
                                {
                                    $match = [$key => $matching];
                                    $this->db->or_where($match);
                                }
                            }
                            else
                            {
                                $this->db->or_where($key, $values);
                            }
                        }
                    }
                    else
                    {
                        $this->db->where($where);
                    }
                }
        
                return $this->db
                  ->order_by('sword_name')
                  ->get("sword_tb")
                  ->result_array();
            }
        
        }
        

        你可能会看块

                                foreach($values as $matching)
                                {
                                    $match = [$key => $matching];
                                    $this->db->or_where($match);
                                }
        

        并在致电where() 之前质疑or_where() 的使用。 Query Builder 足够聪明,可以知道是否添加了任何其他 WHERE,如果不需要,不会在“WHERE”前面加上“OR”。

        让我们看一些用法示例。

        $this->sword_model->getsword();
        

        产生查询语句

        SELECT * FROM Sword_tb ORDER BY Sword_name

        $this->sword_model->getsword('model, sword_name, cost', array('model' => 'Broad'));
        

        生产

        SELECT model, Sword_name, cost FROM Sword_tb WHERE model = Broad ORDER BY Sword_name

        $this->sword_model->getsword(NULL, array('model' => 'Broad', 'cost <' => 100));
        

        SELECT * FROM Sword_tb WHERE model = Broad AND cost

        $this->sword_model->getsword('model, sword_name, cost',
              array('model' => 'Broad, Samurai', 'sword_name' => 'Excalibur'), 'or');
        

        SELECT model, Sword_name, cost FROM Sword_tb WHERE model = Broad OR model = Samurai OR Sword_name = Excalibur ORDER BY Sword_name

        $this->sword_model->getsword(NULL,
              array('model' => 'Broad, Samurai', 'sword_name' => ['Excalibur', 'Fred']), 'or');
        

        SELECT * FROM Sword_tb WHERE model = Broad OR model = Samurai OR Sword_name = Excalibur OR Sword_name = Fred ORDER BY Sword_name

        注意:我从生成的查询字符串中删除了 back-tics,因为在 SO 上它看起来很奇怪。请放心,一切都已妥善逃脱。

        如果您担心速度,我对上述内容进行了基准测试。构建查询语句所需的最长时间为 0.0007 秒。构建所有五个查询总共需要 0.0022 秒 - 每个平均 0.00044。

        注意,现在是构建语句的时候了。检索数据的时间不包括在内,因为……我没有数据。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-01-23
          • 2019-11-01
          • 2013-12-20
          • 1970-01-01
          • 2021-08-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多