CodeIgniter(CI3)框架MY_Model模型类 Version 1.0.0

<?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'], '', '&amp;');
			}
			$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.
	 */
	public 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 protected]', 'name'=>"example")
	 * @param mixed $value i.e. $this->exist('email', '[email protected]')
	 * @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) {
			if ($this->timestamps !== FALSE && !empty($this->_created_at_field)) {
				foreach ($data as &$row) {
					$row[$this->_created_at_field] = $this->_the_timestamp();
				}
			}
			$this->insert_batch($this->table_name, $data);
			return $this->affected_rows();
		} else {
			if($this->timestamps !== FALSE && !empty($this->_created_at_field))
			{
				$data[$this->_created_at_field] = $this->_the_timestamp();
			}
			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_key = '')
	{
		$count = count($data);
		$count_recursive = count($data, COUNT_RECURSIVE);
		if ($count != $count_recursive)
		{
			if($this->timestamps !== FALSE && !empty($this->_updated_at_field))
			{
				foreach ($data as &$row)
				{
					$row[$this->_updated_at_field] = $this->_the_timestamp();
				}
			}
			$this->update_batch($this->table_name, $data, $where_key);
		} else {
			if($this->timestamps !== FALSE && !empty($this->_updated_at_field))
			{
				$data[$this->_updated_at_field] = $this->_the_timestamp();
			}
			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->soft_delete == TRUE)
		{
			$to_update = array();
			foreach($this->result() as $row)
			{
				$to_update[] = array($this->primary_key => $row->{$this->primary_key});
			}
			if(isset($to_update)&& count($to_update) > 0)
			{
				foreach($to_update as &$row)
				{
					//$row = $this->trigger('before_soft_delete',$row);
					$row[$this->_deleted_at_field] = $this->_the_timestamp();
				}
				$affected_rows = $this->db->update_batch($this->table_name, $to_update, $this->primary_key);
			}
			return $affected_rows;
		} else {
			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

猜你喜欢

转载自blog.csdn.net/ppxin/article/details/89566911