CodeIgniter - 最佳模型方法

时间:2017-10-25 06:42:55

标签: php codeigniter

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

控制器,就我而言,是我进行验证,模型调用和数据显示的地方。在模型上,只有一个目的,就是我进行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

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

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

4 个答案:

答案 0 :(得分:1)

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

我一直在使用Codeigniter MVC&amp; HMVC超过2年。第一个是我到目前为止的选择,它帮助我检查和维护我的代码,也有助于我将来的更新/代码。

答案 1 :(得分:1)

您可以尝试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;
    }

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

答案 2 :(得分:1)

我更喜欢一个通用模型,我可以使用它执行所有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,并且可以在所有控制器中使用其所有通用功能。因此,这种方法避免了冗余模型函数来获取,插入和更新数据,并且通过为每个表定义不同的模型来节省我们。

答案 3 :(得分:1)

大多数情况下,多个函数更容易调试,理解和维护。

也就是说,你可以使你的多方法模型代码重复性降低很多。 考虑以下。 (__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();
    }
}

然而,&#34;灵活&#34;方法在某些情况下可能有用。

&#34;单身&#34;之间的速度差异vs&#34;灵活&#34;是微不足道的,不是考虑因素。需要考虑的是&#34;灵活的&#34;当你试图回应更多&#34;条件时,你会很快变得笨拙。

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

你的&#34;灵活的&#34; getsword()的版本至少有一个限制,即您不能选择不属于WHERE子句的列。

在这里使用Query Builder是一种可以实现灵活方法的方法,该方法为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);
                        }

并在致电or_where()之前询问where()的使用情况。查询生成器足够聪明,可以知道是否已添加任何其他WHERE并且不会放置&#34; OR&#34;在&#34; WHERE&#34;前面如果不需要的话。

让我们看看一些用法示例。

$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&lt; 100 ORDER BY sword_name

$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

注意:我从生成的查询字符串中删除了后台抽象,因为在这里它看起来很奇怪。请放心,一切都妥善逃脱。

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

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