CodeIgniter(CI3)MY_Model 模型扩展类 Version 2.0.0 https://mp.csdn.net/postedit/90906165
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* MY_Model Class
* Version 1.0.0
* Instructions:
* 1.Support multi-database.
* 2.Support Pagination.
* 3.Precondition: url and array helper loaded.
* 4.In inherited subclasses, the query-related methods should support chain operations and
* return $this, else should be considered carefully whether support chain operation.
* It is recommended that methods supporting chain operations start with obvious words such as get- and filter-.
* 5.Table Alias "a" added automatically, in method like result(), fetch_sql() and print_sql(), but not in update() and delete().
* 6.Disallow the use of $this->db->from() functions in inheritance sub-classes.
*/
class MY_Model{
private $app = NULL;
protected $db = NULL;
protected $db_group = "default";
protected $table_name = NULL;
protected $primary_key = 'id';
protected $default_limit = 10;
protected $limit = NULL;
protected $page_links = NULL;
protected $_total_count = NULL;
/**
* Class Constructor.
* Adapt database connection group automatically.
* Priorities for using databases: Transferred database parameters > $CI->db
* When the database $CI->db is not the required database, load the corresponding
* database automatically as the $this->db_group.
*/
function __construct()
{
$this->app = &get_instance();
$this->_connect_database();
$this->table_name = empty($this->table_name) ? $this->_guess_table_name() : $this->db->dbprefix($this->table_name);
}
/**
* Attributes that the model does not own will be retrieved from the CI application.
* Equivalent to inheriting CI_Model classes.
*/
public function __get($key)
{
return $this->app->$key;
}
/**
* Connects to the database according to the set $db_group
*/
private function _connect_database()
{
if ($this->db_group != "default")
{
if (isset($this->app->{$this->db_group}) && !empty($this->app->{$this->db_group}))
{
$this->db = $this->app->{$this->db_group};
} else {
$this->db = $this->load->database($this->db_group, TRUE);
$this->app->{$this->db_group} = $this->db;
}
} else {
if (isset($this->app->db) && !empty($this->app->db))
{
$this->db = $this->app->db;
} else {
$this->db = $this->app->db = $this->load->database("default", TRUE);
}
}
}
/**
* Guess the table name when $this->table_name is empty.
* @return string table name with prefix.
*/
private function _guess_table_name()
{
$this->load->helper('inflector');
$model_name = get_class($this);
$table_name = plural(preg_replace('/(_m|_model|_mdl|model)?$/', '', strtolower($model_name)));
$table = $this->db->dbprefix($table_name);
$this->_table_exists($table);
return $table;
}
/**
* Checks if the table exists.
* @param $table_name
* @return bool
*/
private function _table_exists($table_name)
{
if (!$this->db->table_exists($table_name)) {
show_error(
sprintf('While trying to figure out the table name, couldn\'t find an existing table named: <strong>"%s"</strong>.<br />You can set the table name in your model by defining the protected variable <strong>$table_name</strong>.',$table_name),
500,
sprintf('Error trying to figure out table name for model "%s"',get_class($this))
);
}
return TRUE;
}
/**
* Configs pagination of the query.
* @param $p Deal with custom configuration options of the pagination.
* @return mixed The desired pagination options
*/
private function _config_pagination($p = array())
{
if (!empty($p['page']))
{
$tmpl_default = array(
'full_tag_open' => "<ul class='pagination pull-right'>",
'full_tag_close' => "</ul>",
'num_tag_open' => "<li>",
'num_tag_close' => "</li>",
'cur_tag_open' => "<li class='disabled'><li class='active'><a href='#'>",
'cur_tag_close' => "<span class='sr-only'></span></a></li>",
'next_tag_open' => "<li>",
'next_tagl_close' => "</li>",
'prev_tag_open' => "<li>",
'prev_tagl_close' => "</li>",
'first_tag_open' => "<li>",
'first_tagl_close' => "</li>",
'last_tag_open' => "<li>",
'last_tagl_close' => "</li>"
);
$tmpl = array_key_exists('tmpl', $p) ? $p['tmpl'] : $tmpl_default;
$p = array_merge($tmpl, $p);
$p['use_page_numbers'] = element('use_page_numbers', $p, TRUE);
$p['page_query_string'] = element('page_query_string', $p, TRUE);
$p['query_string_segment'] = element('query_string_segment', $p, 'page');
$p['base_url'] = element('base_url', $p, current_url());
$p['base_url'] = element('url', $p, $p['base_url']);
$p['per_page'] = element('per_page', $p, $this->default_limit);
$p['per_page'] = element('limit', $p, $p['per_page']);
$this->limit = $p['per_page'];
if (isset($p['tmpl'])){
unset($p['tmpl']);
}
if (!empty($p['extra']))
{
$p['extra'] = http_build_query($p['extra'], '', '&');
}
$p['base_url'] = empty($p['extra']) ? $p['base_url'] : $p['base_url']."?".$p['extra'];
}
return $p;
}
/**
* Paging query
* @param int $page Current page
* @return $this To implement chain query.
*/
private function _paginate($page, $limit = 0)
{
$limit = empty($limit) ? $this->limit : $limit;
$page = (int)$page;
$page = $page>0 ? $page : 1;
$offset = ($page - 1) * ($limit);
$this->db->limit($limit, $offset);
return $this;
}
/**
* generates paging connections
* @param $config pagination config
* @return mixed paging connection of HTML format
*/
private function _pagination($config)
{
if (!isset($this->pagination))
{
$this->load->library('pagination');
}
$this->pagination->initialize($config);
$page_links = $this->pagination->create_links();
return $page_links;
}
/**
* An example of the simplest chain query method, often used to inherit subclasses
* Support chain operation, and parameters are equivalent to $this->db->where()
* @param mixed i.e. $this->get($id)
* @param mixed
* @param bool
* @return $this to implement chain query
*/
function get($key = NULL, $value = NULL, $escape = NULL)
{
if (empty($key)){
return $this;
}
if (is_numeric($key)){
$this->db->where('id', $key);
} else {
$this->db->where($key, $value, $escape);
}
return $this;
}
/**
* Common query function
* 1.Implementing Paging Function
* 2.To Return Paging Connection, used by get_page_link()
* @param array $pagination configuration for pagination
* @param bool $result_array If TRUE to return array results, Else to return object results.
* @return array of query result
*/
function result($pagination = array(), $result_array = FALSE)
{
$sql = $this->db->get_compiled_select("{$this->table_name} as a", FALSE);
if (!empty($pagination['page']))
{
$pagination = $this->_config_pagination($pagination);
$query = $this->db->query($sql);
$total = $query->num_rows();
$this->_total_count = $total;
if ($total == 0)
{
$this->db->reset_query();
$pagination['total_rows'] = 0;
$this->page_links = "";
return array();
}
$pagination['total_rows'] = $total;
$this->_paginate($this->input->get('page'));
$this->page_links = $this->_pagination($pagination);
}
$query = $this->db->get();
return $result_array ? $query->result_array() : $query->result();
}
/**
* @param array $pagination configuration for pagination
* @return array of query result
*/
function result_array($pagination = array())
{
return $this->result($pagination, TRUE);
}
/**
* return total count of result() or result_array()
* @return int | NULL
*/
function get_total_count()
{
return $this->_total_count;
}
/**
* Gets the pagination link
* Not support chain operation
* @return string pagination link
*/
function create_links()
{
return $this->page_links;
}
/**
* Gets the query result of row, used to key-query.
* Instructions: Not compatible with chain operation.
* @param mixed $key i.e. '12500' or like $this->where($key, $value = NULL, $escape = NULL)
* @param mixed $value
* @param mixed $escape
* @param bool $result_array If TRUE to return array results, Else to return object results
* @return object or array of row result
*/
function get_row($key = NULL, $value = NULL, $escape = NULL, $result_array = FALSE)
{
if (is_numeric($key)){
$this->db->where('id', $key);
} elseif (!empty($key)){
$this->db->where($key, $value, $escape);
}
$query = $this->db->get($this->table_name);
return $result_array ? $query->row_array(): $query->row();
}
/**
* Gets the query result of row, used to key-query.
* Not compatible with chain operation
* @param mixed $key i.e. '12500' or like $this->where($key, $value = NULL, $escape = NULL)
* @param mixed $value
* @param mixed $escape
* @return array of row result
*/
function get_row_array($key = NULL, $value = NULL, $escape = NULL)
{
return $this->get_row($key, $value, $escape, TRUE);
}
/**
* Checks if primary key record exists.
* Parameters are equivalent to $this->db->where()
* @param mixed i.e. '12500' or array('email'=>'12500') or array('email'=>'email@hotmail.com', 'name'=>"example")
* @param mixed $value i.e. $this->exist('email', 'email@hotmail.com')
* @param bool
* @return bool return if exist
*/
function exist($key = NULL, $value = NULL, $escape = NULL)
{
if (is_numeric($key)){
$this->db->where('id', $key);
} elseif (!empty($key)){
$this->db->where($key, $value, $escape);
}
$query = $this->db->limit(1)->get($this->table_name);
return empty($query->row()) ? FALSE : TRUE;
}
/**
* Instructions: $this->get($where)->count();
* @return int Number of query records.
*/
function count()
{
return $this->db->count_all_results($this->table_name);
}
/**
* Add a record or records to the table.
* Not compatible with chain operation
* @param array $data.
* @return false | int inserted record id | affected rows | array(insert_id).
*/
function add($data = array())
{
$count = count($data);
$count_recursive = count($data, COUNT_RECURSIVE);
if ($count != $count_recursive) {
$this->db->insert_batch($this->table_name, $data);
return $this->db->affected_rows();
} else {
foreach ($data as $key => $value) {
$this->db->set($key, $value);
}
$this->db->insert($this->table_name);
if ($this->db->affected_rows() > 0)
{
return $this->db->insert_id();
} else {
return FALSE;
}
}
}
/**
* Updates data of meeting condition
* Instructions: $this->get($where)->update($data);
* @param array $data Parameters for updating data
* @return int updated record count.
*/
function update($data = array(), $where_field = '')
{
$count = count($data);
$count_recursive = count($data, COUNT_RECURSIVE);
if ($count != $count_recursive)
{
$this->db->update_batch($this->table_name, $data, $where_field);
} else {
foreach ($data as $key => $value) {
$this->db->set($key, $value);
}
$this->db->update($this->table_name);
}
return $this->db->affected_rows();
}
/**
* Deletes data of meeting condition
* Instructions: $this->get($where)->delete();
* @return int affected rows.
*/
function delete()
{
$affected_rows = 0;
if ($this->db->delete($this->table_name))
{
$affected_rows = $this->db->affected_rows();
}
return $affected_rows;
}
/**
* resets the query.
*/
function reset_query()
{
$this->db->reset_query();
}
/**
* Manual escape
* @param $value
* @return mixed
*/
function escape($value)
{
return $this->db->escape($value);
}
/**
* debug function
* Instructions: $sql = $this->get($where)->fetch_sql();
*/
function fetch_sql($reset_query = TRUE)
{
$sql = $this->db->get_compiled_select("{$this->table_name} as a", FALSE);
$reset_query === TRUE ? $this->db->reset_query() : NULL;
return $sql;
}
/**
* debug function
* Instructions: $this->get($where)->print_sql(); //default, abort view rendering.
*/
function print_sql($break_off = TRUE, $reset_query = TRUE)
{
$sql = $this->db->get_compiled_select("{$this->table_name} as a", FALSE);
$reset_query === TRUE ? $this->db->reset_query() : NULL;
if ($break_off)
{
exit($sql);
} else {
echo($sql);
}
}
} // end of class