From 5a69b36010c4d03530e764e0bd8257c5b4c87bb3 Mon Sep 17 00:00:00 2001 From: Christian Land Date: Fri, 13 Oct 2017 13:20:58 +0200 Subject: [PATCH 01/10] Format in a PSR2-ish way First pass of cleaning up the code and make it more readable. --- application/libraries/Datatables.php | 1178 +++++++++++++------------- 1 file changed, 599 insertions(+), 579 deletions(-) diff --git a/application/libraries/Datatables.php b/application/libraries/Datatables.php index c6de11f..7e505e6 100644 --- a/application/libraries/Datatables.php +++ b/application/libraries/Datatables.php @@ -1,640 +1,660 @@ - - * @author Vincent Bambico - * Yusuf Ozdemir - * @link http://ellislab.com/forums/viewthread/160896/ - */ + * Ignited Datatables + * + * This is a wrapper class/library based on the native Datatables server-side implementation by Allan Jardine + * found at http://datatables.net/examples/data_sources/server_side.html for CodeIgniter + * + * @package CodeIgniter + * @subpackage libraries + * @category library + * @version 2.0 + * @author Vincent Bambico + * Yusuf Ozdemir + * @link http://ellislab.com/forums/viewthread/160896/ + */ + +if (!defined('BASEPATH')) { + exit('No direct script access allowed'); +} + class Datatables { - /** - * Global container variables for chained argument results - * - */ - private $ci; - private $table; - private $distinct; - private $group_by = array(); - private $select = array(); - private $joins = array(); - private $columns = array(); - private $where = array(); - private $or_where = array(); - private $where_in = array(); - private $like = array(); - private $or_like = array(); - private $filter = array(); - private $add_columns = array(); - private $edit_columns = array(); - private $unset_columns = array(); - - /** - * Copies an instance of CI - */ - public function __construct() - { - $this->ci =& get_instance(); - } - - /** - * If you establish multiple databases in config/database.php this will allow you to - * set the database (other than $active_group) - more info: http://ellislab.com/forums/viewthread/145901/#712942 - */ - public function set_database($db_name) - { - $db_data = $this->ci->load->database($db_name, TRUE); - $this->ci->db = $db_data; - } - - /** - * Generates the SELECT portion of the query - * - * @param string $columns - * @param bool $backtick_protect - * @return mixed - */ - public function select($columns, $backtick_protect = TRUE) - { - foreach($this->explode(',', $columns) as $val) + /** + * Global container variables for chained argument results + * + */ + private $ci; + private $table; + private $distinct; + private $group_by = array(); + private $select = array(); + private $joins = array(); + private $columns = array(); + private $where = array(); + private $or_where = array(); + private $where_in = array(); + private $like = array(); + private $or_like = array(); + private $filter = array(); + private $add_columns = array(); + private $edit_columns = array(); + private $unset_columns = array(); + + /** + * Copies an instance of CI + */ + public function __construct() + { + $this->ci =& get_instance(); + } + + /** + * If you establish multiple databases in config/database.php this will allow you to + * set the database (other than $active_group) - more info: http://ellislab.com/forums/viewthread/145901/#712942 + * @param mixed $db_name + */ + public function set_database($db_name) + { + $db_data = $this->ci->load->database($db_name, true); + $this->ci->db = $db_data; + } + + /** + * Generates the SELECT portion of the query + * + * @param string $columns + * @param bool $backtick_protect + * @return mixed + */ + public function select($columns, $backtick_protect = true) + { + foreach ($this->explode(',', $columns) as $val) { + $column = trim(preg_replace('/(.*)\s+as\s+(\w*)/i', '$2', $val)); + $column = preg_replace('/.*\.(.*)/i', '$1', $column); // get name after `.` + $this->columns[] = $column; + $this->select[$column] = trim(preg_replace('/(.*)\s+as\s+(\w*)/i', '$1', $val)); + } + + $this->ci->db->select($columns, $backtick_protect); + return $this; + } + + /** + * Generates the DISTINCT portion of the query + * + * @param string $column + * @return mixed + */ + public function distinct($column) + { + $this->distinct = $column; + $this->ci->db->distinct($column); + return $this; + } + + /** + * Generates a custom GROUP BY portion of the query + * + * @param string $val + * @return mixed + */ + public function group_by($val) { - $column = trim(preg_replace('/(.*)\s+as\s+(\w*)/i', '$2', $val)); - $column = preg_replace('/.*\.(.*)/i', '$1', $column); // get name after `.` - $this->columns[] = $column; - $this->select[$column] = trim(preg_replace('/(.*)\s+as\s+(\w*)/i', '$1', $val)); + $this->group_by[] = $val; + $this->ci->db->group_by($val); + return $this; } - $this->ci->db->select($columns, $backtick_protect); - return $this; - } - - /** - * Generates the DISTINCT portion of the query - * - * @param string $column - * @return mixed - */ - public function distinct($column) - { - $this->distinct = $column; - $this->ci->db->distinct($column); - return $this; - } - - /** - * Generates a custom GROUP BY portion of the query - * - * @param string $val - * @return mixed - */ - public function group_by($val) - { - $this->group_by[] = $val; - $this->ci->db->group_by($val); - return $this; - } - - /** - * Generates the FROM portion of the query - * - * @param string $table - * @return mixed - */ - public function from($table) - { - $this->table = $table; - return $this; - } - - /** - * Generates the JOIN portion of the query - * - * @param string $table - * @param string $fk - * @param string $type - * @return mixed - */ - public function join($table, $fk, $type = NULL) - { - $this->joins[] = array($table, $fk, $type); - $this->ci->db->join($table, $fk, $type); - return $this; - } - - /** - * Generates the WHERE portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function where($key_condition, $val = NULL, $backtick_protect = TRUE) - { - $this->where[] = array($key_condition, $val, $backtick_protect); - $this->ci->db->where($key_condition, $val, $backtick_protect); - return $this; - } - - /** - * Generates the WHERE portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function or_where($key_condition, $val = NULL, $backtick_protect = TRUE) - { - $this->or_where[] = array($key_condition, $val, $backtick_protect); - $this->ci->db->or_where($key_condition, $val, $backtick_protect); - return $this; - } + /** + * Generates the FROM portion of the query + * + * @param string $table + * @return mixed + */ + public function from($table) + { + $this->table = $table; + return $this; + } + + /** + * Generates the JOIN portion of the query + * + * @param string $table + * @param string $fk + * @param string $type + * @return mixed + */ + public function join($table, $fk, $type = null) + { + $this->joins[] = array($table, $fk, $type); + $this->ci->db->join($table, $fk, $type); + return $this; + } + + /** + * Generates the WHERE portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @return mixed + */ + public function where($key_condition, $val = null, $backtick_protect = true) + { + $this->where[] = array($key_condition, $val, $backtick_protect); + $this->ci->db->where($key_condition, $val, $backtick_protect); + return $this; + } + + /** + * Generates the WHERE portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @return mixed + */ + public function or_where($key_condition, $val = null, $backtick_protect = true) + { + $this->or_where[] = array($key_condition, $val, $backtick_protect); + $this->ci->db->or_where($key_condition, $val, $backtick_protect); + return $this; + } - /** - * Generates the WHERE IN portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function where_in($key_condition, $val = NULL) - { - $this->where_in[] = array($key_condition, $val); - $this->ci->db->where_in($key_condition, $val); - return $this; - } - - /** - * Generates the WHERE portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function filter($key_condition, $val = NULL, $backtick_protect = TRUE) - { - $this->filter[] = array($key_condition, $val, $backtick_protect); - return $this; - } - - /** - * Generates a %LIKE% portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function like($key_condition, $val = NULL, $side = 'both') - { - $this->like[] = array($key_condition, $val, $side); - $this->ci->db->like($key_condition, $val, $side); - return $this; - } - - /** - * Generates the OR %LIKE% portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function or_like($key_condition, $val = NULL, $side = 'both') - { - $this->or_like[] = array($key_condition, $val, $side); - $this->ci->db->or_like($key_condition, $val, $side); - return $this; - } - - /** - * Sets additional column variables for adding custom columns - * - * @param string $column - * @param string $content - * @param string $match_replacement - * @return mixed - */ - public function add_column($column, $content, $match_replacement = NULL) - { - $this->add_columns[$column] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); - return $this; - } - - /** - * Sets additional column variables for editing columns - * - * @param string $column - * @param string $content - * @param string $match_replacement - * @return mixed - */ - public function edit_column($column, $content, $match_replacement) - { - $this->edit_columns[$column][] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); - return $this; - } - - /** - * Unset column - * - * @param string $column - * @return mixed - */ - public function unset_column($column) - { - $column=explode(',',$column); - $this->unset_columns=array_merge($this->unset_columns,$column); - return $this; - } - - /** - * Builds all the necessary query segments and performs the main query based on results set from chained statements - * - * @param string $output - * @param string $charset - * @return string - */ - public function generate($output = 'json', $charset = 'UTF-8') - { - if(strtolower($output) == 'json') - $this->get_paging(); - - $this->get_ordering(); - $this->get_filtering(); - return $this->produce_output(strtolower($output), strtolower($charset)); - } - - /** - * Generates the LIMIT portion of the query - * - * @return mixed - */ - private function get_paging() - { - $iStart = $this->ci->input->post('start'); - $iLength = $this->ci->input->post('length'); - - if($iLength != '' && $iLength != '-1') - $this->ci->db->limit($iLength, ($iStart)? $iStart : 0); - } - - /** - * Generates the ORDER BY portion of the query - * - * @return mixed - */ - private function get_ordering() - { - - $Data = $this->ci->input->post('columns'); - - - if ($this->ci->input->post('order')) - foreach ($this->ci->input->post('order') as $key) - if($this->check_cType()) - $this->ci->db->order_by($Data[$key['column']]['data'], $key['dir']); - else - $this->ci->db->order_by($this->columns[$key['column']] , $key['dir']); - - } - - /** - * Generates a %LIKE% portion of the query - * - * @return mixed - */ - private function get_filtering() - { - - $mColArray = $this->ci->input->post('columns'); - - $sWhere = ''; - $search = $this->ci->input->post('search'); - $sSearch = $this->ci->db->escape_like_str(trim($search['value'])); - $columns = array_values(array_diff($this->columns, $this->unset_columns)); - - if($sSearch != '') - for($i = 0; $i < count($mColArray); $i++) - if ($mColArray[$i]['searchable'] == 'true' && !array_key_exists($mColArray[$i]['data'], $this->add_columns)) - if($this->check_cType()) - $sWhere .= $this->select[$mColArray[$i]['data']] . " LIKE '%" . $sSearch . "%' OR "; - else - $sWhere .= $this->select[$this->columns[$i]] . " LIKE '%" . $sSearch . "%' OR "; - - - $sWhere = substr_replace($sWhere, '', -3); - - if($sWhere != '') - $this->ci->db->where('(' . $sWhere . ')'); - - // TODO : sRangeSeparator - - foreach($this->filter as $val) - $this->ci->db->where($val[0], $val[1], $val[2]); - } - - /** - * Compiles the select statement based on the other functions called and runs the query - * - * @return mixed - */ - private function get_display_result() - { - return $this->ci->db->get($this->table); - } - - /** - * Builds an encoded string data. Returns JSON by default, and an array of aaData if output is set to raw. - * - * @param string $output - * @param string $charset - * @return mixed - */ - private function produce_output($output, $charset) - { - $aaData = array(); - $rResult = $this->get_display_result(); - - if($output == 'json') + /** + * Generates the WHERE IN portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @return mixed + */ + public function where_in($key_condition, $val = null) { - $iTotal = $this->get_total_results(); - $iFilteredTotal = $this->get_total_results(TRUE); + $this->where_in[] = array($key_condition, $val); + $this->ci->db->where_in($key_condition, $val); + return $this; + } + + /** + * Generates the WHERE portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @return mixed + */ + public function filter($key_condition, $val = null, $backtick_protect = true) + { + $this->filter[] = array($key_condition, $val, $backtick_protect); + return $this; + } + + /** + * Generates a %LIKE% portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @param mixed $side + * @return mixed + */ + public function like($key_condition, $val = null, $side = 'both') + { + $this->like[] = array($key_condition, $val, $side); + $this->ci->db->like($key_condition, $val, $side); + return $this; + } + + /** + * Generates the OR %LIKE% portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @param mixed $side + * @return mixed + */ + public function or_like($key_condition, $val = null, $side = 'both') + { + $this->or_like[] = array($key_condition, $val, $side); + $this->ci->db->or_like($key_condition, $val, $side); + return $this; + } + + /** + * Sets additional column variables for adding custom columns + * + * @param string $column + * @param string $content + * @param string $match_replacement + * @return mixed + */ + public function add_column($column, $content, $match_replacement = null) + { + $this->add_columns[$column] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); + return $this; + } + + /** + * Sets additional column variables for editing columns + * + * @param string $column + * @param string $content + * @param string $match_replacement + * @return mixed + */ + public function edit_column($column, $content, $match_replacement) + { + $this->edit_columns[$column][] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); + return $this; + } + + /** + * Unset column + * + * @param string $column + * @return mixed + */ + public function unset_column($column) + { + $column=explode(',', $column); + $this->unset_columns=array_merge($this->unset_columns, $column); + return $this; + } + + /** + * Builds all the necessary query segments and performs the main query based on results set from chained statements + * + * @param string $output + * @param string $charset + * @return string + */ + public function generate($output = 'json', $charset = 'UTF-8') + { + if (strtolower($output) == 'json') { + $this->get_paging(); + } + + $this->get_ordering(); + $this->get_filtering(); + return $this->produce_output(strtolower($output), strtolower($charset)); + } + + /** + * Generates the LIMIT portion of the query + * + * @return mixed + */ + private function get_paging() + { + $iStart = $this->ci->input->post('start'); + $iLength = $this->ci->input->post('length'); + + if ($iLength != '' && $iLength != '-1') { + $this->ci->db->limit($iLength, ($iStart) ? $iStart : 0); + } + } + + /** + * Generates the ORDER BY portion of the query + * + * @return mixed + */ + private function get_ordering() + { + $Data = $this->ci->input->post('columns'); + + + if ($this->ci->input->post('order')) { + foreach ($this->ci->input->post('order') as $key) { + if ($this->check_cType()) { + $this->ci->db->order_by($Data[$key['column']]['data'], $key['dir']); + } else { + $this->ci->db->order_by($this->columns[$key['column']], $key['dir']); + } + } + } } - foreach($rResult->result_array() as $row_key => $row_val) + /** + * Generates a %LIKE% portion of the query + * + * @return mixed + */ + private function get_filtering() { - $aaData[$row_key] = ($this->check_cType())? $row_val : array_values($row_val); + $mColArray = $this->ci->input->post('columns'); + + $sWhere = ''; + $search = $this->ci->input->post('search'); + $sSearch = $this->ci->db->escape_like_str(trim($search['value'])); + $columns = array_values(array_diff($this->columns, $this->unset_columns)); + + if ($sSearch != '') { + for ($i = 0; $i < count($mColArray); $i++) { + if ($mColArray[$i]['searchable'] == 'true' && !array_key_exists($mColArray[$i]['data'], $this->add_columns)) { + if ($this->check_cType()) { + $sWhere .= $this->select[$mColArray[$i]['data']] . " LIKE '%" . $sSearch . "%' OR "; + } else { + $sWhere .= $this->select[$this->columns[$i]] . " LIKE '%" . $sSearch . "%' OR "; + } + } + } + } - foreach($this->add_columns as $field => $val) - if($this->check_cType()) - $aaData[$row_key][$field] = $this->exec_replace($val, $aaData[$row_key]); - else - $aaData[$row_key][] = $this->exec_replace($val, $aaData[$row_key]); + $sWhere = substr_replace($sWhere, '', -3); - foreach($this->edit_columns as $modkey => $modval) - foreach($modval as $val) - $aaData[$row_key][($this->check_cType())? $modkey : array_search($modkey, $this->columns)] = $this->exec_replace($val, $aaData[$row_key]); + if ($sWhere != '') { + $this->ci->db->where('(' . $sWhere . ')'); + } - $aaData[$row_key] = array_diff_key($aaData[$row_key], ($this->check_cType())? $this->unset_columns : array_intersect($this->columns, $this->unset_columns)); + // TODO : sRangeSeparator - if(!$this->check_cType()) - $aaData[$row_key] = array_values($aaData[$row_key]); + foreach ($this->filter as $val) { + $this->ci->db->where($val[0], $val[1], $val[2]); + } + } + /** + * Compiles the select statement based on the other functions called and runs the query + * + * @return mixed + */ + private function get_display_result() + { + return $this->ci->db->get($this->table); } - if($output == 'json') + /** + * Builds an encoded string data. Returns JSON by default, and an array of aaData if output is set to raw. + * + * @param string $output + * @param string $charset + * @return mixed + */ + private function produce_output($output, $charset) { - $sOutput = array - ( + $aaData = array(); + $rResult = $this->get_display_result(); + + if ($output == 'json') { + $iTotal = $this->get_total_results(); + $iFilteredTotal = $this->get_total_results(true); + } + + foreach ($rResult->result_array() as $row_key => $row_val) { + $aaData[$row_key] = ($this->check_cType()) ? $row_val : array_values($row_val); + + foreach ($this->add_columns as $field => $val) { + if ($this->check_cType()) { + $aaData[$row_key][$field] = $this->exec_replace($val, $aaData[$row_key]); + } else { + $aaData[$row_key][] = $this->exec_replace($val, $aaData[$row_key]); + } + } + + + foreach ($this->edit_columns as $modkey => $modval) { + foreach ($modval as $val) { + $aaData[$row_key][($this->check_cType()) ? $modkey : array_search($modkey, $this->columns)] = $this->exec_replace($val, $aaData[$row_key]); + } + } + + $aaData[$row_key] = array_diff_key($aaData[$row_key], ($this->check_cType()) ? $this->unset_columns : array_intersect($this->columns, $this->unset_columns)); + + if (!$this->check_cType()) { + $aaData[$row_key] = array_values($aaData[$row_key]); + } + } + + if ($output == 'json') { + $sOutput = array( 'draw' => intval($this->ci->input->post('draw')), 'recordsTotal' => $iTotal, 'recordsFiltered' => $iFilteredTotal, 'data' => $aaData ); - if($charset == 'utf-8') - return json_encode($sOutput); - else - return $this->jsonify($sOutput); + if ($charset == 'utf-8') { + return json_encode($sOutput); + } else { + return $this->jsonify($sOutput); + } + } else { + return array('aaData' => $aaData); + } } - else - return array('aaData' => $aaData); - } - - /** - * Get result count - * - * @return integer - */ - private function get_total_results($filtering = FALSE) - { - if($filtering) - $this->get_filtering(); - - foreach($this->joins as $val) - $this->ci->db->join($val[0], $val[1], $val[2]); - - foreach($this->where as $val) - $this->ci->db->where($val[0], $val[1], $val[2]); - - foreach($this->or_where as $val) - $this->ci->db->or_where($val[0], $val[1], $val[2]); + + /** + * Get result count + * + * @param mixed $filtering + * @return integer + */ + private function get_total_results($filtering = false) + { + if ($filtering) { + $this->get_filtering(); + } + + foreach ($this->joins as $val) { + $this->ci->db->join($val[0], $val[1], $val[2]); + } + + foreach ($this->where as $val) { + $this->ci->db->where($val[0], $val[1], $val[2]); + } + + foreach ($this->or_where as $val) { + $this->ci->db->or_where($val[0], $val[1], $val[2]); + } - foreach($this->where_in as $val) - $this->ci->db->where_in($val[0], $val[1]); + foreach ($this->where_in as $val) { + $this->ci->db->where_in($val[0], $val[1]); + } - foreach($this->group_by as $val) - $this->ci->db->group_by($val); + foreach ($this->group_by as $val) { + $this->ci->db->group_by($val); + } - foreach($this->like as $val) - $this->ci->db->like($val[0], $val[1], $val[2]); + foreach ($this->like as $val) { + $this->ci->db->like($val[0], $val[1], $val[2]); + } - foreach($this->or_like as $val) - $this->ci->db->or_like($val[0], $val[1], $val[2]); + foreach ($this->or_like as $val) { + $this->ci->db->or_like($val[0], $val[1], $val[2]); + } - if(strlen($this->distinct) > 0) - { - $this->ci->db->distinct($this->distinct); - $this->ci->db->select($this->columns); + if (strlen($this->distinct) > 0) { + $this->ci->db->distinct($this->distinct); + $this->ci->db->select($this->columns); + } + + $query = $this->ci->db->get($this->table, null, null, false); + return $query->num_rows(); } - $query = $this->ci->db->get($this->table, NULL, NULL, FALSE); - return $query->num_rows(); - } - - /** - * Runs callback functions and makes replacements - * - * @param mixed $custom_val - * @param mixed $row_data - * @return string $custom_val['content'] - */ - private function exec_replace($custom_val, $row_data) - { - $replace_string = ''; + /** + * Runs callback functions and makes replacements + * + * @param mixed $custom_val + * @param mixed $row_data + * @return string $custom_val['content'] + */ + private function exec_replace($custom_val, $row_data) + { + $replace_string = ''; - // Go through our array backwards, else $1 (foo) will replace $11, $12 etc with foo1, foo2 etc - $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); + // Go through our array backwards, else $1 (foo) will replace $11, $12 etc with foo1, foo2 etc + $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); + + if (isset($custom_val['replacement']) && is_array($custom_val['replacement'])) { + //Added this line because when the replacement has over 10 elements replaced the variable "$1" first by the "$10" + $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); + foreach ($custom_val['replacement'] as $key => $val) { + $sval = preg_replace("/(? $args_val) { + $args_val = preg_replace("/(?columns)) ? ($row_data[($this->check_cType()) ? $args_val : array_search($args_val, $this->columns)]) : $args_val; + } + + $replace_string = call_user_func_array($func, $args); + } elseif (in_array($sval, $this->columns)) { + $replace_string = $row_data[($this->check_cType()) ? $sval : array_search($sval, $this->columns)]; + } else { + $replace_string = $sval; + } + + $custom_val['content'] = str_ireplace('$' . ($key + 1), $replace_string, $custom_val['content']); + } + } + + return $custom_val['content']; + } - if(isset($custom_val['replacement']) && is_array($custom_val['replacement'])) + /** + * Check column type -numeric or column name + * + * @return bool + */ + private function check_cType() { - //Added this line because when the replacement has over 10 elements replaced the variable "$1" first by the "$10" - $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); - foreach($custom_val['replacement'] as $key => $val) - { - $sval = preg_replace("/(? $args_val) - { - $args_val = preg_replace("/(?columns))? ($row_data[($this->check_cType())? $args_val : array_search($args_val, $this->columns)]) : $args_val; - } - - $replace_string = call_user_func_array($func, $args); + $column = $this->ci->input->post('columns'); + if (is_numeric($column[0]['data'])) { + return false; + } else { + return true; } - elseif(in_array($sval, $this->columns)) - $replace_string = $row_data[($this->check_cType())? $sval : array_search($sval, $this->columns)]; - else - $replace_string = $sval; - - $custom_val['content'] = str_ireplace('$' . ($key + 1), $replace_string, $custom_val['content']); - } } - return $custom_val['content']; - } - - /** - * Check column type -numeric or column name - * - * @return bool - */ - private function check_cType() - { - $column = $this->ci->input->post('columns'); - if(is_numeric($column[0]['data'])) - return FALSE; - else - return TRUE; - } - - - /** - * Return the difference of open and close characters - * - * @param string $str - * @param string $open - * @param string $close - * @return string $retval - */ - private function balanceChars($str, $open, $close) - { - $openCount = substr_count($str, $open); - $closeCount = substr_count($str, $close); - $retval = $openCount - $closeCount; - return $retval; - } - - /** - * Explode, but ignore delimiter until closing characters are found - * - * @param string $delimiter - * @param string $str - * @param string $open - * @param string $close - * @return mixed $retval - */ - private function explode($delimiter, $str, $open = '(', $close=')') - { - $retval = array(); - $hold = array(); - $balance = 0; - $parts = explode($delimiter, $str); - - foreach($parts as $part) + + /** + * Return the difference of open and close characters + * + * @param string $str + * @param string $open + * @param string $close + * @return string $retval + */ + private function balanceChars($str, $open, $close) { - $hold[] = $part; - $balance += $this->balanceChars($part, $open, $close); + $openCount = substr_count($str, $open); + $closeCount = substr_count($str, $close); + $retval = $openCount - $closeCount; + return $retval; + } - if($balance < 1) - { - $retval[] = implode($delimiter, $hold); + /** + * Explode, but ignore delimiter until closing characters are found + * + * @param string $delimiter + * @param string $str + * @param string $open + * @param string $close + * @return mixed $retval + */ + private function explode($delimiter, $str, $open = '(', $close=')') + { + $retval = array(); $hold = array(); $balance = 0; - } - } + $parts = explode($delimiter, $str); - if(count($hold) > 0) - $retval[] = implode($delimiter, $hold); + foreach ($parts as $part) { + $hold[] = $part; + $balance += $this->balanceChars($part, $open, $close); - return $retval; - } - - /** - * Workaround for json_encode's UTF-8 encoding if a different charset needs to be used - * - * @param mixed $result - * @return string - */ - private function jsonify($result = FALSE) - { - if(is_null($result)) - return 'null'; + if ($balance < 1) { + $retval[] = implode($delimiter, $hold); + $hold = array(); + $balance = 0; + } + } - if($result === FALSE) - return 'false'; + if (count($hold) > 0) { + $retval[] = implode($delimiter, $hold); + } - if($result === TRUE) - return 'true'; + return $retval; + } - if(is_scalar($result)) + /** + * Workaround for json_encode's UTF-8 encoding if a different charset needs to be used + * + * @param mixed $result + * @return string + */ + private function jsonify($result = false) { - if(is_float($result)) - return floatval(str_replace(',', '.', strval($result))); - - if(is_string($result)) - { - static $jsonReplaces = array(array('\\', '/', '\n', '\t', '\r', '\b', '\f', '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"')); - return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $result) . '"'; - } - else - return $result; - } + if (is_null($result)) { + return 'null'; + } - $isList = TRUE; + if ($result === false) { + return 'false'; + } - for($i = 0, reset($result); $i < count($result); $i++, next($result)) - { - if(key($result) !== $i) - { - $isList = FALSE; - break; - } - } + if ($result === true) { + return 'true'; + } - $json = array(); + if (is_scalar($result)) { + if (is_float($result)) { + return floatval(str_replace(',', '.', strval($result))); + } + + if (is_string($result)) { + static $jsonReplaces = array(array('\\', '/', '\n', '\t', '\r', '\b', '\f', '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"')); + return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $result) . '"'; + } else { + return $result; + } + } - if($isList) - { - foreach($result as $value) - $json[] = $this->jsonify($value); + $isList = true; - return '[' . join(',', $json) . ']'; + for ($i = 0, reset($result); $i < count($result); $i++, next($result)) { + if (key($result) !== $i) { + $isList = false; + break; + } + } + + $json = array(); + + if ($isList) { + foreach ($result as $value) { + $json[] = $this->jsonify($value); + } + + return '[' . join(',', $json) . ']'; + } else { + foreach ($result as $key => $value) { + $json[] = $this->jsonify($key) . ':' . $this->jsonify($value); + } + + return '{' . join(',', $json) . '}'; + } } - else + + /** + * returns the sql statement of the last query run + * @return type + */ + public function last_query() { - foreach($result as $key => $value) - $json[] = $this->jsonify($key) . ':' . $this->jsonify($value); - - return '{' . join(',', $json) . '}'; + return $this->ci->db->last_query(); } - } - - /** - * returns the sql statement of the last query run - * @return type - */ - public function last_query() - { - return $this->ci->db->last_query(); - } } /* End of file Datatables.php */ /* Location: ./application/libraries/Datatables.php */ From ac50fb0894dbcc9c4910aeb914d9af63ae903e9e Mon Sep 17 00:00:00 2001 From: Christian Land Date: Fri, 13 Oct 2017 13:44:37 +0200 Subject: [PATCH 02/10] More code-cleanup --- .gitignore | 2 + application/libraries/Datatables.php | 1457 ++++++++++++++------------ 2 files changed, 803 insertions(+), 656 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..431a836 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +application/libraries/Datatables.php~ diff --git a/application/libraries/Datatables.php b/application/libraries/Datatables.php index 7e505e6..053f1f6 100644 --- a/application/libraries/Datatables.php +++ b/application/libraries/Datatables.php @@ -1,660 +1,805 @@ - * @author Vincent Bambico - * Yusuf Ozdemir - * @link http://ellislab.com/forums/viewthread/160896/ - */ - -if (!defined('BASEPATH')) { - exit('No direct script access allowed'); -} - - class Datatables - { - /** - * Global container variables for chained argument results - * - */ - private $ci; - private $table; - private $distinct; - private $group_by = array(); - private $select = array(); - private $joins = array(); - private $columns = array(); - private $where = array(); - private $or_where = array(); - private $where_in = array(); - private $like = array(); - private $or_like = array(); - private $filter = array(); - private $add_columns = array(); - private $edit_columns = array(); - private $unset_columns = array(); - - /** - * Copies an instance of CI - */ - public function __construct() - { - $this->ci =& get_instance(); - } - - /** - * If you establish multiple databases in config/database.php this will allow you to - * set the database (other than $active_group) - more info: http://ellislab.com/forums/viewthread/145901/#712942 - * @param mixed $db_name - */ - public function set_database($db_name) - { - $db_data = $this->ci->load->database($db_name, true); - $this->ci->db = $db_data; - } - - /** - * Generates the SELECT portion of the query - * - * @param string $columns - * @param bool $backtick_protect - * @return mixed - */ - public function select($columns, $backtick_protect = true) - { - foreach ($this->explode(',', $columns) as $val) { - $column = trim(preg_replace('/(.*)\s+as\s+(\w*)/i', '$2', $val)); - $column = preg_replace('/.*\.(.*)/i', '$1', $column); // get name after `.` - $this->columns[] = $column; - $this->select[$column] = trim(preg_replace('/(.*)\s+as\s+(\w*)/i', '$1', $val)); - } - - $this->ci->db->select($columns, $backtick_protect); - return $this; - } - - /** - * Generates the DISTINCT portion of the query - * - * @param string $column - * @return mixed - */ - public function distinct($column) - { - $this->distinct = $column; - $this->ci->db->distinct($column); - return $this; - } - - /** - * Generates a custom GROUP BY portion of the query - * - * @param string $val - * @return mixed - */ - public function group_by($val) - { - $this->group_by[] = $val; - $this->ci->db->group_by($val); - return $this; - } - - /** - * Generates the FROM portion of the query - * - * @param string $table - * @return mixed - */ - public function from($table) - { - $this->table = $table; - return $this; - } - - /** - * Generates the JOIN portion of the query - * - * @param string $table - * @param string $fk - * @param string $type - * @return mixed - */ - public function join($table, $fk, $type = null) - { - $this->joins[] = array($table, $fk, $type); - $this->ci->db->join($table, $fk, $type); - return $this; - } - - /** - * Generates the WHERE portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function where($key_condition, $val = null, $backtick_protect = true) - { - $this->where[] = array($key_condition, $val, $backtick_protect); - $this->ci->db->where($key_condition, $val, $backtick_protect); - return $this; - } - - /** - * Generates the WHERE portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function or_where($key_condition, $val = null, $backtick_protect = true) - { - $this->or_where[] = array($key_condition, $val, $backtick_protect); - $this->ci->db->or_where($key_condition, $val, $backtick_protect); - return $this; - } - - /** - * Generates the WHERE IN portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function where_in($key_condition, $val = null) - { - $this->where_in[] = array($key_condition, $val); - $this->ci->db->where_in($key_condition, $val); - return $this; - } - - /** - * Generates the WHERE portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ - public function filter($key_condition, $val = null, $backtick_protect = true) - { - $this->filter[] = array($key_condition, $val, $backtick_protect); - return $this; - } - - /** - * Generates a %LIKE% portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @param mixed $side - * @return mixed - */ - public function like($key_condition, $val = null, $side = 'both') - { - $this->like[] = array($key_condition, $val, $side); - $this->ci->db->like($key_condition, $val, $side); - return $this; - } - - /** - * Generates the OR %LIKE% portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @param mixed $side - * @return mixed - */ - public function or_like($key_condition, $val = null, $side = 'both') - { - $this->or_like[] = array($key_condition, $val, $side); - $this->ci->db->or_like($key_condition, $val, $side); - return $this; - } - - /** - * Sets additional column variables for adding custom columns - * - * @param string $column - * @param string $content - * @param string $match_replacement - * @return mixed - */ - public function add_column($column, $content, $match_replacement = null) - { - $this->add_columns[$column] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); - return $this; - } - - /** - * Sets additional column variables for editing columns - * - * @param string $column - * @param string $content - * @param string $match_replacement - * @return mixed - */ - public function edit_column($column, $content, $match_replacement) - { - $this->edit_columns[$column][] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); - return $this; - } - - /** - * Unset column - * - * @param string $column - * @return mixed - */ - public function unset_column($column) - { - $column=explode(',', $column); - $this->unset_columns=array_merge($this->unset_columns, $column); - return $this; - } - - /** - * Builds all the necessary query segments and performs the main query based on results set from chained statements - * - * @param string $output - * @param string $charset - * @return string - */ - public function generate($output = 'json', $charset = 'UTF-8') - { - if (strtolower($output) == 'json') { - $this->get_paging(); - } - - $this->get_ordering(); - $this->get_filtering(); - return $this->produce_output(strtolower($output), strtolower($charset)); - } - - /** - * Generates the LIMIT portion of the query - * - * @return mixed - */ - private function get_paging() - { - $iStart = $this->ci->input->post('start'); - $iLength = $this->ci->input->post('length'); - - if ($iLength != '' && $iLength != '-1') { - $this->ci->db->limit($iLength, ($iStart) ? $iStart : 0); - } - } - - /** - * Generates the ORDER BY portion of the query - * - * @return mixed - */ - private function get_ordering() - { - $Data = $this->ci->input->post('columns'); - - - if ($this->ci->input->post('order')) { - foreach ($this->ci->input->post('order') as $key) { - if ($this->check_cType()) { - $this->ci->db->order_by($Data[$key['column']]['data'], $key['dir']); - } else { - $this->ci->db->order_by($this->columns[$key['column']], $key['dir']); - } - } - } - } - - /** - * Generates a %LIKE% portion of the query - * - * @return mixed - */ - private function get_filtering() - { - $mColArray = $this->ci->input->post('columns'); - - $sWhere = ''; - $search = $this->ci->input->post('search'); - $sSearch = $this->ci->db->escape_like_str(trim($search['value'])); - $columns = array_values(array_diff($this->columns, $this->unset_columns)); - - if ($sSearch != '') { - for ($i = 0; $i < count($mColArray); $i++) { - if ($mColArray[$i]['searchable'] == 'true' && !array_key_exists($mColArray[$i]['data'], $this->add_columns)) { - if ($this->check_cType()) { - $sWhere .= $this->select[$mColArray[$i]['data']] . " LIKE '%" . $sSearch . "%' OR "; - } else { - $sWhere .= $this->select[$this->columns[$i]] . " LIKE '%" . $sSearch . "%' OR "; - } - } - } - } - - - $sWhere = substr_replace($sWhere, '', -3); - - if ($sWhere != '') { - $this->ci->db->where('(' . $sWhere . ')'); - } - - // TODO : sRangeSeparator - - foreach ($this->filter as $val) { - $this->ci->db->where($val[0], $val[1], $val[2]); - } - } - - /** - * Compiles the select statement based on the other functions called and runs the query - * - * @return mixed - */ - private function get_display_result() - { - return $this->ci->db->get($this->table); - } - - /** - * Builds an encoded string data. Returns JSON by default, and an array of aaData if output is set to raw. - * - * @param string $output - * @param string $charset - * @return mixed - */ - private function produce_output($output, $charset) - { - $aaData = array(); - $rResult = $this->get_display_result(); - - if ($output == 'json') { - $iTotal = $this->get_total_results(); - $iFilteredTotal = $this->get_total_results(true); - } - - foreach ($rResult->result_array() as $row_key => $row_val) { - $aaData[$row_key] = ($this->check_cType()) ? $row_val : array_values($row_val); - - foreach ($this->add_columns as $field => $val) { - if ($this->check_cType()) { - $aaData[$row_key][$field] = $this->exec_replace($val, $aaData[$row_key]); - } else { - $aaData[$row_key][] = $this->exec_replace($val, $aaData[$row_key]); - } - } - - - foreach ($this->edit_columns as $modkey => $modval) { - foreach ($modval as $val) { - $aaData[$row_key][($this->check_cType()) ? $modkey : array_search($modkey, $this->columns)] = $this->exec_replace($val, $aaData[$row_key]); - } - } - - $aaData[$row_key] = array_diff_key($aaData[$row_key], ($this->check_cType()) ? $this->unset_columns : array_intersect($this->columns, $this->unset_columns)); - - if (!$this->check_cType()) { - $aaData[$row_key] = array_values($aaData[$row_key]); - } - } - - if ($output == 'json') { - $sOutput = array( - 'draw' => intval($this->ci->input->post('draw')), - 'recordsTotal' => $iTotal, - 'recordsFiltered' => $iFilteredTotal, - 'data' => $aaData - ); - - if ($charset == 'utf-8') { - return json_encode($sOutput); - } else { - return $this->jsonify($sOutput); - } - } else { - return array('aaData' => $aaData); - } - } - - /** - * Get result count - * - * @param mixed $filtering - * @return integer - */ - private function get_total_results($filtering = false) - { - if ($filtering) { - $this->get_filtering(); - } - - foreach ($this->joins as $val) { - $this->ci->db->join($val[0], $val[1], $val[2]); - } - - foreach ($this->where as $val) { - $this->ci->db->where($val[0], $val[1], $val[2]); - } - - foreach ($this->or_where as $val) { - $this->ci->db->or_where($val[0], $val[1], $val[2]); - } - - foreach ($this->where_in as $val) { - $this->ci->db->where_in($val[0], $val[1]); - } - - foreach ($this->group_by as $val) { - $this->ci->db->group_by($val); - } - - foreach ($this->like as $val) { - $this->ci->db->like($val[0], $val[1], $val[2]); - } - - foreach ($this->or_like as $val) { - $this->ci->db->or_like($val[0], $val[1], $val[2]); - } - - if (strlen($this->distinct) > 0) { - $this->ci->db->distinct($this->distinct); - $this->ci->db->select($this->columns); - } - - $query = $this->ci->db->get($this->table, null, null, false); - return $query->num_rows(); - } - - /** - * Runs callback functions and makes replacements - * - * @param mixed $custom_val - * @param mixed $row_data - * @return string $custom_val['content'] - */ - private function exec_replace($custom_val, $row_data) - { - $replace_string = ''; - - // Go through our array backwards, else $1 (foo) will replace $11, $12 etc with foo1, foo2 etc - $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); - - if (isset($custom_val['replacement']) && is_array($custom_val['replacement'])) { - //Added this line because when the replacement has over 10 elements replaced the variable "$1" first by the "$10" - $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); - foreach ($custom_val['replacement'] as $key => $val) { - $sval = preg_replace("/(? $args_val) { - $args_val = preg_replace("/(?columns)) ? ($row_data[($this->check_cType()) ? $args_val : array_search($args_val, $this->columns)]) : $args_val; - } - - $replace_string = call_user_func_array($func, $args); - } elseif (in_array($sval, $this->columns)) { - $replace_string = $row_data[($this->check_cType()) ? $sval : array_search($sval, $this->columns)]; - } else { - $replace_string = $sval; - } - - $custom_val['content'] = str_ireplace('$' . ($key + 1), $replace_string, $custom_val['content']); - } - } - - return $custom_val['content']; - } - - /** - * Check column type -numeric or column name - * - * @return bool - */ - private function check_cType() - { - $column = $this->ci->input->post('columns'); - if (is_numeric($column[0]['data'])) { - return false; - } else { - return true; - } - } - - - /** - * Return the difference of open and close characters - * - * @param string $str - * @param string $open - * @param string $close - * @return string $retval - */ - private function balanceChars($str, $open, $close) - { - $openCount = substr_count($str, $open); - $closeCount = substr_count($str, $close); - $retval = $openCount - $closeCount; - return $retval; - } - - /** - * Explode, but ignore delimiter until closing characters are found - * - * @param string $delimiter - * @param string $str - * @param string $open - * @param string $close - * @return mixed $retval - */ - private function explode($delimiter, $str, $open = '(', $close=')') - { - $retval = array(); - $hold = array(); - $balance = 0; - $parts = explode($delimiter, $str); - - foreach ($parts as $part) { - $hold[] = $part; - $balance += $this->balanceChars($part, $open, $close); - - if ($balance < 1) { - $retval[] = implode($delimiter, $hold); - $hold = array(); - $balance = 0; - } - } - - if (count($hold) > 0) { - $retval[] = implode($delimiter, $hold); - } - - return $retval; - } - - /** - * Workaround for json_encode's UTF-8 encoding if a different charset needs to be used - * - * @param mixed $result - * @return string - */ - private function jsonify($result = false) - { - if (is_null($result)) { - return 'null'; - } - - if ($result === false) { - return 'false'; - } - - if ($result === true) { - return 'true'; - } - - if (is_scalar($result)) { - if (is_float($result)) { - return floatval(str_replace(',', '.', strval($result))); - } - - if (is_string($result)) { - static $jsonReplaces = array(array('\\', '/', '\n', '\t', '\r', '\b', '\f', '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"')); - return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $result) . '"'; - } else { - return $result; - } - } - - $isList = true; - - for ($i = 0, reset($result); $i < count($result); $i++, next($result)) { - if (key($result) !== $i) { - $isList = false; - break; - } - } - - $json = array(); - - if ($isList) { - foreach ($result as $value) { - $json[] = $this->jsonify($value); - } - - return '[' . join(',', $json) . ']'; - } else { - foreach ($result as $key => $value) { - $json[] = $this->jsonify($key) . ':' . $this->jsonify($value); - } - - return '{' . join(',', $json) . '}'; - } - } - - /** - * returns the sql statement of the last query run - * @return type - */ - public function last_query() - { - return $this->ci->db->last_query(); - } - } + /** + * Ignited Datatables + * + * This is a wrapper class/library based on the native Datatables server-side implementation by Allan Jardine + * found at http://datatables.net/examples/data_sources/server_side.html for CodeIgniter + * + * @package CodeIgniter + * @subpackage libraries + * @category library + * @version 2.0 + * @author Vincent Bambico + * Yusuf Ozdemir + * @link http://ellislab.com/forums/viewthread/160896/ + */ + + if (!defined('BASEPATH')) { + exit('No direct script access allowed'); + } + + class Datatables { + + /** + * Global container variables for chained argument results + */ + + private $ci; + private $table; + private $distinct; + private $group_by = array(); + private $select = array(); + private $joins = array(); + private $columns = array(); + private $where = array(); + private $or_where = array(); + private $where_in = array(); + private $like = array(); + private $or_like = array(); + private $filter = array(); + private $add_columns = array(); + private $edit_columns = array(); + private $unset_columns = array(); + + /** + * Copies an instance of CI + */ + + public function __construct() { + + $this->ci =& get_instance(); + + } + + /** + * If you establish multiple databases in config/database.php this will allow you to + * set the database (other than $active_group) - more info: https://www.codeigniter.com/userguide3/database/connecting.html#connecting-to-multiple-databases + * + * @param mixed $db_name + */ + + public function set_database($db_name) { + + $db_data = $this->ci->load->database($db_name, true); + $this->ci->db = $db_data; + + } + + /** + * Generates the SELECT portion of the query + * + * @param string $columns + * @param bool $backtick_protect + * @return mixed + */ + + public function select($columns, $backtick_protect = true) { + + foreach ($this->explode(',', $columns) as $val) { + + $column = trim(preg_replace('/(.*)\s+as\s+(\w*)/i', '$2', $val)); + $column = preg_replace('/.*\.(.*)/i', '$1', $column); // get name after `.` + + $this->columns[] = $column; + + $this->select[$column] = trim(preg_replace('/(.*)\s+as\s+(\w*)/i', '$1', $val)); + + } + + $this->ci->db->select($columns, $backtick_protect); + + return $this; + + } + + /** + * Generates the DISTINCT portion of the query + * + * @param string $column + * @return mixed + */ + + public function distinct($column) { + + $this->distinct = $column; + $this->ci->db->distinct($column); + + return $this; + + } + + /** + * Generates a custom GROUP BY portion of the query + * + * @param string $val + * @return mixed + */ + + public function group_by($val) { + + $this->group_by[] = $val; + $this->ci->db->group_by($val); + + return $this; + + } + + /** + * Generates the FROM portion of the query + * + * @param string $table + * @return mixed + */ + + public function from($table) { + + $this->table = $table; + + return $this; + + } + + /** + * Generates the JOIN portion of the query + * + * @param string $table + * @param string $fk + * @param string $type + * @return mixed + */ + + public function join($table, $fk, $type = null) { + + $this->joins[] = array($table, $fk, $type); + $this->ci->db->join($table, $fk, $type); + + return $this; + + } + + /** + * Generates the WHERE portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @return mixed + */ + + public function where($key_condition, $val = null, $backtick_protect = true) { + + $this->where[] = array($key_condition, $val, $backtick_protect); + $this->ci->db->where($key_condition, $val, $backtick_protect); + + return $this; + + } + + /** + * Generates the WHERE portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @return mixed + */ + + public function or_where($key_condition, $val = null, $backtick_protect = true) { + + $this->or_where[] = array($key_condition, $val, $backtick_protect); + $this->ci->db->or_where($key_condition, $val, $backtick_protect); + + return $this; + + } + + /** + * Generates the WHERE IN portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @return mixed + */ + + public function where_in($key_condition, $val = null) { + + $this->where_in[] = array($key_condition, $val); + $this->ci->db->where_in($key_condition, $val); + + return $this; + + } + + /** + * Generates the WHERE portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @return mixed + */ + + public function filter($key_condition, $val = null, $backtick_protect = true) { + + $this->filter[] = array($key_condition, $val, $backtick_protect); + + return $this; + + } + + /** + * Generates a %LIKE% portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @param mixed $side + * @return mixed + */ + + public function like($key_condition, $val = null, $side = 'both') { + + $this->like[] = array($key_condition, $val, $side); + $this->ci->db->like($key_condition, $val, $side); + + return $this; + + } + + /** + * Generates the OR %LIKE% portion of the query + * + * @param mixed $key_condition + * @param string $val + * @param bool $backtick_protect + * @param mixed $side + * @return mixed + */ + + public function or_like($key_condition, $val = null, $side = 'both') { + + $this->or_like[] = array($key_condition, $val, $side); + $this->ci->db->or_like($key_condition, $val, $side); + + return $this; + + } + + /** + * Sets additional column variables for adding custom columns + * + * @param string $column + * @param string $content + * @param string $match_replacement + * @return mixed + */ + + public function add_column($column, $content, $match_replacement = null) { + + $this->add_columns[$column] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); + + return $this; + + } + + /** + * Sets additional column variables for editing columns + * + * @param string $column + * @param string $content + * @param string $match_replacement + * @return mixed + */ + + public function edit_column($column, $content, $match_replacement) { + + $this->edit_columns[$column][] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); + + return $this; + + } + + /** + * Unset column + * + * @param string $column + * @return mixed + */ + + public function unset_column($column) { + + $column = explode(',', $column); + $this->unset_columns=array_merge($this->unset_columns, $column); + + return $this; + + } + + /** + * Builds all the necessary query segments and performs the main query based on results set from chained statements + * + * @param string $output + * @param string $charset + * @return string + */ + + public function generate($output = 'json', $charset = 'UTF-8') { + + if (strtolower($output) == 'json') { + $this->get_paging(); + } + + $this->get_ordering(); + $this->get_filtering(); + + return $this->produce_output(strtolower($output), strtolower($charset)); + + } + + /** + * Generates the LIMIT portion of the query + * + * @return mixed + */ + + private function get_paging() { + + $iStart = $this->ci->input->post('start'); + $iLength = $this->ci->input->post('length'); + + if ($iLength != '' && $iLength != '-1') { + $this->ci->db->limit($iLength, ($iStart) ? $iStart : 0); + } + + } + + /** + * Generates the ORDER BY portion of the query + * + * @return mixed + */ + + private function get_ordering() { + + $Data = $this->ci->input->post('columns'); + + if ($this->ci->input->post('order')) { + + foreach ($this->ci->input->post('order') as $key) { + + if ($this->check_cType()) { + + $this->ci->db->order_by($Data[$key['column']]['data'], $key['dir']); + + } else { + + $this->ci->db->order_by($this->columns[$key['column']], $key['dir']); + + } + + } + + } + + } + + /** + * Generates a %LIKE% portion of the query + * + * @return mixed + */ + + private function get_filtering() { + + $mColArray = $this->ci->input->post('columns'); + + $sWhere = ''; + $search = $this->ci->input->post('search'); + $sSearch = $this->ci->db->escape_like_str(trim($search['value'])); + $columns = array_values(array_diff($this->columns, $this->unset_columns)); + + if ($sSearch != '') { + + for ($i = 0; $i < count($mColArray); $i++) { + + if ($mColArray[$i]['searchable'] == 'true' && !array_key_exists($mColArray[$i]['data'], $this->add_columns)) { + + if ($this->check_cType()) { + + $sWhere .= $this->select[$mColArray[$i]['data']] . " LIKE '%" . $sSearch . "%' OR "; + + } else { + + $sWhere .= $this->select[$this->columns[$i]] . " LIKE '%" . $sSearch . "%' OR "; + + } + + } + + } + + } + + $sWhere = substr_replace($sWhere, '', -3); + + if ($sWhere != '') { + $this->ci->db->where('(' . $sWhere . ')'); + } + + // TODO : sRangeSeparator + + foreach ($this->filter as $val) { + $this->ci->db->where($val[0], $val[1], $val[2]); + } + + } + + /** + * Compiles the select statement based on the other functions called and runs the query + * + * @return mixed + */ + + private function get_display_result() { + + return $this->ci->db->get($this->table); + + } + + /** + * Builds an encoded string data. Returns JSON by default, and an array of aaData if output is set to raw. + * + * @param string $output + * @param string $charset + * @return mixed + */ + + private function produce_output($output, $charset) { + + $aaData = array(); + $rResult = $this->get_display_result(); + + if ($output == 'json') { + $iTotal = $this->get_total_results(); + $iFilteredTotal = $this->get_total_results(true); + } + + foreach ($rResult->result_array() as $row_key => $row_val) { + + $aaData[$row_key] = ($this->check_cType()) ? $row_val : array_values($row_val); + + foreach ($this->add_columns as $field => $val) { + + if ($this->check_cType()) { + + $aaData[$row_key][$field] = $this->exec_replace($val, $aaData[$row_key]); + + } else { + + $aaData[$row_key][] = $this->exec_replace($val, $aaData[$row_key]); + + } + + } + + + foreach ($this->edit_columns as $modkey => $modval) { + + foreach ($modval as $val) { + + $aaData[$row_key][($this->check_cType()) ? $modkey : array_search($modkey, $this->columns)] = $this->exec_replace($val, $aaData[$row_key]); + + } + + } + + $aaData[$row_key] = array_diff_key($aaData[$row_key], ($this->check_cType()) ? $this->unset_columns : array_intersect($this->columns, $this->unset_columns)); + + if (!$this->check_cType()) { + + $aaData[$row_key] = array_values($aaData[$row_key]); + + } + + } + + if ($output == 'json') { + + $sOutput = array('draw' => intval($this->ci->input->post('draw')), + 'recordsTotal' => $iTotal, + 'recordsFiltered' => $iFilteredTotal, + 'data' => $aaData ); + + if ($charset == 'utf-8') { + return json_encode($sOutput); + } else { + return $this->jsonify($sOutput); + } + + } else { + + return array('aaData' => $aaData); + + } + + } + + /** + * Get result count + * + * @param mixed $filtering + * @return integer + */ + + private function get_total_results($filtering = false) { + + if ($filtering) { + $this->get_filtering(); + } + + foreach ($this->joins as $val) { + $this->ci->db->join($val[0], $val[1], $val[2]); + } + + foreach ($this->where as $val) { + $this->ci->db->where($val[0], $val[1], $val[2]); + } + + foreach ($this->or_where as $val) { + $this->ci->db->or_where($val[0], $val[1], $val[2]); + } + + foreach ($this->where_in as $val) { + $this->ci->db->where_in($val[0], $val[1]); + } + + foreach ($this->group_by as $val) { + $this->ci->db->group_by($val); + } + + foreach ($this->like as $val) { + $this->ci->db->like($val[0], $val[1], $val[2]); + } + + foreach ($this->or_like as $val) { + $this->ci->db->or_like($val[0], $val[1], $val[2]); + } + + if (strlen($this->distinct) > 0) { + $this->ci->db->distinct($this->distinct); + $this->ci->db->select($this->columns); + } + + $query = $this->ci->db->get($this->table, null, null, false); + + return $query->num_rows(); + + } + + /** + * Runs callback functions and makes replacements + * + * @param mixed $custom_val + * @param mixed $row_data + * @return string $custom_val['content'] + */ + + private function exec_replace($custom_val, $row_data) { + + $replace_string = ''; + + // Go through our array backwards, else $1 (foo) will replace $11, $12 etc with foo1, foo2 etc + $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); + + if (isset($custom_val['replacement']) && is_array($custom_val['replacement'])) { + + //Added this line because when the replacement has over 10 elements replaced the variable "$1" first by the "$10" + $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); + + foreach ($custom_val['replacement'] as $key => $val) { + + $sval = preg_replace("/(? $args_val) { + $args_val = preg_replace("/(?columns)) ? ($row_data[($this->check_cType()) ? $args_val : array_search($args_val, $this->columns)]) : $args_val; + } + + $replace_string = call_user_func_array($func, $args); + + } elseif (in_array($sval, $this->columns)) { + + $replace_string = $row_data[($this->check_cType()) ? $sval : array_search($sval, $this->columns)]; + + } else { + + $replace_string = $sval; + } + + $custom_val['content'] = str_ireplace('$' . ($key + 1), $replace_string, $custom_val['content']); + + } + + } + + return $custom_val['content']; + + } + + /** + * Check column type -numeric or column name + * + * @return bool + */ + + private function check_cType() { + + $column = $this->ci->input->post('columns'); + + if (is_numeric($column[0]['data'])) { + return false; + } else { + return true; + } + + } + + /** + * Return the difference of open and close characters + * + * @param string $str + * @param string $open + * @param string $close + * @return string $retval + */ + + private function balanceChars($str, $open, $close) { + + $openCount = substr_count($str, $open); + $closeCount = substr_count($str, $close); + + $retval = $openCount - $closeCount; + + return $retval; + + } + + /** + * Explode, but ignore delimiter until closing characters are found + * + * @param string $delimiter + * @param string $str + * @param string $open + * @param string $close + * @return mixed $retval + */ + + private function explode($delimiter, $str, $open = '(', $close=')') { + + $retval = array(); + $hold = array(); + $balance = 0; + $parts = explode($delimiter, $str); + + foreach ($parts as $part) { + + $hold[] = $part; + $balance += $this->balanceChars($part, $open, $close); + + if ($balance < 1) { + $retval[] = implode($delimiter, $hold); + $hold = array(); + $balance = 0; + } + + } + + if (count($hold) > 0) { + + $retval[] = implode($delimiter, $hold); + + } + + return $retval; + + } + + /** + * Workaround for json_encode's UTF-8 encoding if a different charset needs to be used + * + * @param mixed $result + * @return string + */ + + private function jsonify($result = false) { + + if (is_null($result)) { + return 'null'; + } + + if ($result === false) { + return 'false'; + } + + if ($result === true) { + return 'true'; + } + + if (is_scalar($result)) { + + if (is_float($result)) { + return floatval(str_replace(',', '.', strval($result))); + } + + if (is_string($result)) { + + static $jsonReplaces = array(array('\\', '/', '\n', '\t', '\r', '\b', '\f', '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"')); + + return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $result) . '"'; + + } else { + + return $result; + + } + + } + + $isList = true; + + for ($i = 0, reset($result); $i < count($result); $i++, next($result)) { + + if (key($result) !== $i) { + + $isList = false; + + break; + + } + + } + + $json = array(); + + if ($isList) { + + foreach ($result as $value) { + $json[] = $this->jsonify($value); + } + + return '[' . join(',', $json) . ']'; + + } else { + + foreach ($result as $key => $value) { + $json[] = $this->jsonify($key) . ':' . $this->jsonify($value); + } + + return '{' . join(',', $json) . '}'; + + } + + } + + /** + * returns the sql statement of the last query run + * @return type + */ + + public function last_query() { + + return $this->ci->db->last_query(); + + } + + } + /* End of file Datatables.php */ /* Location: ./application/libraries/Datatables.php */ From 43e955bb95e43dc1282b05ff8ff133080361e82c Mon Sep 17 00:00:00 2001 From: Christian Land Date: Fri, 13 Oct 2017 13:58:48 +0200 Subject: [PATCH 03/10] Get rid of numeric keys Renamed a bunch of variables to reflect the CI-nomenclature. Replaced numeric array-keys with more meaningful ones to make everybodies life easier. --- application/libraries/Datatables.php | 211 +++++++++++++++------------ 1 file changed, 120 insertions(+), 91 deletions(-) diff --git a/application/libraries/Datatables.php b/application/libraries/Datatables.php index 053f1f6..5420b3c 100644 --- a/application/libraries/Datatables.php +++ b/application/libraries/Datatables.php @@ -28,19 +28,19 @@ class Datatables { private $ci; private $table; private $distinct; - private $group_by = array(); - private $select = array(); - private $joins = array(); - private $columns = array(); - private $where = array(); - private $or_where = array(); - private $where_in = array(); - private $like = array(); - private $or_like = array(); - private $filter = array(); - private $add_columns = array(); - private $edit_columns = array(); - private $unset_columns = array(); + private $group_by = array(); + private $select = array(); + private $joins = array(); + private $columns = array(); + private $where = array(); + private $or_where = array(); + private $where_in = array(); + private $like = array(); + private $or_like = array(); + private $filter = array(); + private $add_columns = array(); + private $edit_columns = array(); + private $unset_columns = array(); /** * Copies an instance of CI @@ -70,16 +70,16 @@ public function set_database($db_name) { * Generates the SELECT portion of the query * * @param string $columns - * @param bool $backtick_protect + * @param bool $escape * @return mixed */ - public function select($columns, $backtick_protect = true) { + public function select($columns, $escape = true) { foreach ($this->explode(',', $columns) as $val) { $column = trim(preg_replace('/(.*)\s+as\s+(\w*)/i', '$2', $val)); - $column = preg_replace('/.*\.(.*)/i', '$1', $column); // get name after `.` + $column = preg_replace('/.*\.(.*)/i', '$1', $column); // get name after `.` $this->columns[] = $column; @@ -87,7 +87,7 @@ public function select($columns, $backtick_protect = true) { } - $this->ci->db->select($columns, $backtick_protect); + $this->ci->db->select($columns, $escape); return $this; @@ -112,14 +112,17 @@ public function distinct($column) { /** * Generates a custom GROUP BY portion of the query * - * @param string $val + * @param string $value + * @param bool $escape * @return mixed */ - public function group_by($val) { + public function group_by($value, $escape = true) { - $this->group_by[] = $val; - $this->ci->db->group_by($val); + $this->group_by[] = array('value' => $value, + 'escape' => $escape); + + $this->ci->db->group_by($value, $escape); return $this; @@ -134,7 +137,7 @@ public function group_by($val) { public function from($table) { - $this->table = $table; + $this->table = $table; return $this; @@ -143,16 +146,21 @@ public function from($table) { /** * Generates the JOIN portion of the query * - * @param string $table - * @param string $fk - * @param string $type + * @param string $table + * @param string $cond + * @param string $type + * @param null|mixed $escape * @return mixed */ - public function join($table, $fk, $type = null) { + public function join($table, $cond, $type = null, $escape = null) { - $this->joins[] = array($table, $fk, $type); - $this->ci->db->join($table, $fk, $type); + $this->joins[] = array('table' => $table, + 'cond' => $cond, + 'type' => $type, + 'escape' => $escape); + + $this->ci->db->join($table, $cond, $type, $escape); return $this; @@ -161,16 +169,19 @@ public function join($table, $fk, $type = null) { /** * Generates the WHERE portion of the query * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect + * @param mixed $key + * @param string $value + * @param bool $escape * @return mixed */ - public function where($key_condition, $val = null, $backtick_protect = true) { + public function where($key, $value = null, $escape = true) { - $this->where[] = array($key_condition, $val, $backtick_protect); - $this->ci->db->where($key_condition, $val, $backtick_protect); + $this->where[] = array('key' => $key, + 'value' => $value, + 'escape' => $escape); + + $this->ci->db->where($key, $value, $escape); return $this; @@ -179,34 +190,40 @@ public function where($key_condition, $val = null, $backtick_protect = true) { /** * Generates the WHERE portion of the query * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect + * @param mixed $key + * @param string $value + * @param bool $escape * @return mixed */ - public function or_where($key_condition, $val = null, $backtick_protect = true) { + public function or_where($key, $value = null, $escape = true) { - $this->or_where[] = array($key_condition, $val, $backtick_protect); - $this->ci->db->or_where($key_condition, $val, $backtick_protect); + $this->or_where[] = array('key' => $key, + 'value' => $value, + 'escape' => $escape); + + $this->ci->db->or_where($key, $value, $escape); return $this; } /** - * Generates the WHERE IN portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @return mixed - */ + * Generates the WHERE IN portion of the query + * + * @param mixed $key + * @param string $value + * @param bool $escape + * @return mixed + */ - public function where_in($key_condition, $val = null) { + public function where_in($key, $value = null, $escape = true) { - $this->where_in[] = array($key_condition, $val); - $this->ci->db->where_in($key_condition, $val); + $this->where_in[] = array('key' => $key, + 'value' => $value, + 'escape' => $escape); + + $this->ci->db->where_in($key, $value, $escape); return $this; @@ -215,34 +232,40 @@ public function where_in($key_condition, $val = null) { /** * Generates the WHERE portion of the query * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect + * @param mixed $key + * @param string $value + * @param bool $escape * @return mixed */ - public function filter($key_condition, $val = null, $backtick_protect = true) { + public function filter($key, $value = null, $escape = true) { - $this->filter[] = array($key_condition, $val, $backtick_protect); + $this->filter[] = array('key' => $key, + 'value' => $value, + 'escape' => $escape); return $this; } /** - * Generates a %LIKE% portion of the query - * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @param mixed $side - * @return mixed - */ + * Generates a %LIKE% portion of the query + * + * @param mixed $field + * @param string $match + * @param mixed $side + * @param bool $escape + * @return mixed + */ - public function like($key_condition, $val = null, $side = 'both') { + public function like($field, $match = '', $side = 'both', $escape = NULL) { - $this->like[] = array($key_condition, $val, $side); - $this->ci->db->like($key_condition, $val, $side); + $this->like[] = array('field' => $field, + 'match' => $match, + 'side' => $side, + 'escape' => $escape); + + $this->ci->db->like($field, $match, $side, $escape); return $this; @@ -251,17 +274,21 @@ public function like($key_condition, $val = null, $side = 'both') { /** * Generates the OR %LIKE% portion of the query * - * @param mixed $key_condition - * @param string $val - * @param bool $backtick_protect - * @param mixed $side + * @param mixed $field + * @param string $match + * @param mixed $side + * @param bool $escape * @return mixed */ - public function or_like($key_condition, $val = null, $side = 'both') { + public function or_like($field, $match = '', $side = 'both', $escape = NULL) { - $this->or_like[] = array($key_condition, $val, $side); - $this->ci->db->or_like($key_condition, $val, $side); + $this->or_like[] = array('field' => $field, + 'match' => $match, + 'side' => $side, + 'escape' => $escape); + + $this->ci->db->or_like($field, $match, $side, $escape); return $this; @@ -270,15 +297,16 @@ public function or_like($key_condition, $val = null, $side = 'both') { /** * Sets additional column variables for adding custom columns * - * @param string $column - * @param string $content - * @param string $match_replacement + * @param string $column + * @param string $content + * @param mixed $match_replacement * @return mixed */ public function add_column($column, $content, $match_replacement = null) { - $this->add_columns[$column] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); + $this->add_columns[$column] = array('content' => $content, + 'replacement' => $this->explode(',', $match_replacement) ); return $this; @@ -287,15 +315,16 @@ public function add_column($column, $content, $match_replacement = null) { /** * Sets additional column variables for editing columns * - * @param string $column - * @param string $content - * @param string $match_replacement + * @param string $column + * @param string $content + * @param mixed $match_replacement * @return mixed */ public function edit_column($column, $content, $match_replacement) { - $this->edit_columns[$column][] = array('content' => $content, 'replacement' => $this->explode(',', $match_replacement)); + $this->edit_columns[$column][] = array('content' => $content, + 'replacement' => $this->explode(',', $match_replacement) ); return $this; @@ -310,8 +339,8 @@ public function edit_column($column, $content, $match_replacement) { public function unset_column($column) { - $column = explode(',', $column); - $this->unset_columns=array_merge($this->unset_columns, $column); + $column = explode(',', $column); + $this->unset_columns = array_merge($this->unset_columns, $column); return $this; @@ -431,7 +460,7 @@ private function get_filtering() { // TODO : sRangeSeparator foreach ($this->filter as $val) { - $this->ci->db->where($val[0], $val[1], $val[2]); + $this->ci->db->where($val['key'], $val['value'], $val['escape']); } } @@ -540,31 +569,31 @@ private function get_total_results($filtering = false) { } foreach ($this->joins as $val) { - $this->ci->db->join($val[0], $val[1], $val[2]); + $this->ci->db->join($val['table'], $val['cond'], $val['type'], $val['escape']); } foreach ($this->where as $val) { - $this->ci->db->where($val[0], $val[1], $val[2]); + $this->ci->db->where($val['key'], $val['value'], $val['escape']); } foreach ($this->or_where as $val) { - $this->ci->db->or_where($val[0], $val[1], $val[2]); + $this->ci->db->or_where($val['key'], $val['value'], $val['escape']); } foreach ($this->where_in as $val) { - $this->ci->db->where_in($val[0], $val[1]); + $this->ci->db->where_in($val['key'], $val['value'], $val['escape']); } foreach ($this->group_by as $val) { - $this->ci->db->group_by($val); + $this->ci->db->group_by($val['value'], $val['escape']); } foreach ($this->like as $val) { - $this->ci->db->like($val[0], $val[1], $val[2]); + $this->ci->db->like($val['field'], $val['match'], $val['side'], 'escape'); } foreach ($this->or_like as $val) { - $this->ci->db->or_like($val[0], $val[1], $val[2]); + $this->ci->db->or_like($val['field'], $val['match'], $val['side'], 'escape'); } if (strlen($this->distinct) > 0) { From 813e54bf4de36ff0350c6d61849b8b10d468090a Mon Sep 17 00:00:00 2001 From: Christian Land Date: Fri, 13 Oct 2017 14:39:48 +0200 Subject: [PATCH 04/10] Fixing some issues This basically just adds some fixes for various issues: https://github.com/IgnitedDatatables/Ignited-Datatables/issues/84 https://github.com/IgnitedDatatables/Ignited-Datatables/issues/78 https://github.com/IgnitedDatatables/Ignited-Datatables/issues/66 --- application/libraries/Datatables.php | 67 ++++++++++++++++------------ 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/application/libraries/Datatables.php b/application/libraries/Datatables.php index 5420b3c..844aa05 100644 --- a/application/libraries/Datatables.php +++ b/application/libraries/Datatables.php @@ -136,7 +136,8 @@ public function group_by($value, $escape = true) { */ public function from($table) { - + + $this->ci->db->from($table); // Issue #78, fix by oobi $this->table = $table; return $this; @@ -339,7 +340,7 @@ public function edit_column($column, $content, $match_replacement) { public function unset_column($column) { - $column = explode(',', $column); + $column = array_flip(explode(',', $column)); // Issue #66, fix by ajindam $this->unset_columns = array_merge($this->unset_columns, $column); return $this; @@ -356,14 +357,14 @@ public function unset_column($column) { public function generate($output = 'json', $charset = 'UTF-8') { - if (strtolower($output) == 'json') { + if (trim(strtolower($output)) == 'json') { $this->get_paging(); } $this->get_ordering(); $this->get_filtering(); - return $this->produce_output(strtolower($output), strtolower($charset)); + return $this->produce_output($output, $charset); } @@ -473,7 +474,7 @@ private function get_filtering() { private function get_display_result() { - return $this->ci->db->get($this->table); + return $this->ci->db->get(); // Issue #78, fix by oobi } @@ -487,27 +488,31 @@ private function get_display_result() { private function produce_output($output, $charset) { - $aaData = array(); - $rResult = $this->get_display_result(); + $aaData = array(); + $output = trim(strtolower($output)); + $charset = trim(strtolower($charset)); + $rResult = $this->get_display_result(); if ($output == 'json') { - $iTotal = $this->get_total_results(); - $iFilteredTotal = $this->get_total_results(true); + + $iTotal = $this->get_total_results(); + $iFilteredTotal = $this->get_total_results(true); + } foreach ($rResult->result_array() as $row_key => $row_val) { - $aaData[$row_key] = ($this->check_cType()) ? $row_val : array_values($row_val); + $aaData[$row_key] = ($this->check_cType()) ? $row_val : array_values($row_val); foreach ($this->add_columns as $field => $val) { if ($this->check_cType()) { - $aaData[$row_key][$field] = $this->exec_replace($val, $aaData[$row_key]); + $aaData[$row_key][$field] = $this->exec_replace($val, $aaData[$row_key]); } else { - $aaData[$row_key][] = $this->exec_replace($val, $aaData[$row_key]); + $aaData[$row_key][] = $this->exec_replace($val, $aaData[$row_key]); } @@ -518,17 +523,17 @@ private function produce_output($output, $charset) { foreach ($modval as $val) { - $aaData[$row_key][($this->check_cType()) ? $modkey : array_search($modkey, $this->columns)] = $this->exec_replace($val, $aaData[$row_key]); + $aaData[$row_key][($this->check_cType()) ? $modkey : array_search($modkey, $this->columns)] = $this->exec_replace($val, $aaData[$row_key]); } } - $aaData[$row_key] = array_diff_key($aaData[$row_key], ($this->check_cType()) ? $this->unset_columns : array_intersect($this->columns, $this->unset_columns)); + $aaData[$row_key] = array_diff_key($aaData[$row_key], ($this->check_cType()) ? $this->unset_columns : array_intersect($this->columns, $this->unset_columns)); if (!$this->check_cType()) { - $aaData[$row_key] = array_values($aaData[$row_key]); + $aaData[$row_key] = array_values($aaData[$row_key]); } @@ -568,6 +573,9 @@ private function get_total_results($filtering = false) { $this->get_filtering(); } + // Set FROM early so table aliases are respected - Issue #78, fix by oobi + $this->ci->db->from($this->table); + foreach ($this->joins as $val) { $this->ci->db->join($val['table'], $val['cond'], $val['type'], $val['escape']); } @@ -601,7 +609,7 @@ private function get_total_results($filtering = false) { $this->ci->db->select($this->columns); } - $query = $this->ci->db->get($this->table, null, null, false); + $query = $this->ci->db->get(null, null, null, false); return $query->num_rows(); @@ -617,42 +625,45 @@ private function get_total_results($filtering = false) { private function exec_replace($custom_val, $row_data) { - $replace_string = ''; + $replace_string = ''; // Go through our array backwards, else $1 (foo) will replace $11, $12 etc with foo1, foo2 etc - $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); + $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); if (isset($custom_val['replacement']) && is_array($custom_val['replacement'])) { //Added this line because when the replacement has over 10 elements replaced the variable "$1" first by the "$10" - $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); + $custom_val['replacement'] = array_reverse($custom_val['replacement'], true); foreach ($custom_val['replacement'] as $key => $val) { - $sval = preg_replace("/(? $args_val) { - $args_val = preg_replace("/(?columns)) ? ($row_data[($this->check_cType()) ? $args_val : array_search($args_val, $this->columns)]) : $args_val; + + $args_val = preg_replace("/(?columns)) ? ($row_data[($this->check_cType()) ? $args_val : array_search($args_val, $this->columns)]) : $args_val; + } - $replace_string = call_user_func_array($func, $args); + $replace_string = call_user_func_array($func, $args); } elseif (in_array($sval, $this->columns)) { - $replace_string = $row_data[($this->check_cType()) ? $sval : array_search($sval, $this->columns)]; + $replace_string = $row_data[($this->check_cType()) ? $sval : array_search($sval, $this->columns)]; } else { - $replace_string = $sval; + $replace_string = $sval; + } - $custom_val['content'] = str_ireplace('$' . ($key + 1), $replace_string, $custom_val['content']); + $custom_val['content'] = str_ireplace('$'.($key + 1), $replace_string, $custom_val['content']); } From cd80d68758f13821d2536f8e7cf2337cd702f2f1 Mon Sep 17 00:00:00 2001 From: Christian Land Date: Fri, 13 Oct 2017 15:01:27 +0200 Subject: [PATCH 05/10] Some minor fixes Added caching to check_cType to improve performance a bit. Cleaned a few things up. --- application/libraries/Datatables.php | 209 ++++++++++++++++----------- 1 file changed, 127 insertions(+), 82 deletions(-) diff --git a/application/libraries/Datatables.php b/application/libraries/Datatables.php index 844aa05..74d3d3d 100644 --- a/application/libraries/Datatables.php +++ b/application/libraries/Datatables.php @@ -9,7 +9,7 @@ * @package CodeIgniter * @subpackage libraries * @category library - * @version 2.0 + * @version 2.0.1 * @author Vincent Bambico * Yusuf Ozdemir * @link http://ellislab.com/forums/viewthread/160896/ @@ -69,6 +69,8 @@ public function set_database($db_name) { /** * Generates the SELECT portion of the query * + * @since 2.0.1 Changed some variable names for consistency + * * @param string $columns * @param bool $escape * @return mixed @@ -112,6 +114,8 @@ public function distinct($column) { /** * Generates a custom GROUP BY portion of the query * + * @since 2.0.1 Changed all variable names and switched to meaningful array-keys + * * @param string $value * @param bool $escape * @return mixed @@ -119,7 +123,7 @@ public function distinct($column) { public function group_by($value, $escape = true) { - $this->group_by[] = array('value' => $value, + $this->group_by[] = array('value' => $value, 'escape' => $escape); $this->ci->db->group_by($value, $escape); @@ -131,12 +135,14 @@ public function group_by($value, $escape = true) { /** * Generates the FROM portion of the query * + * @since 2.0.1 Changed all variable names and switched to meaningful array-keys + * * @param string $table * @return mixed */ public function from($table) { - + $this->ci->db->from($table); // Issue #78, fix by oobi $this->table = $table; @@ -147,6 +153,8 @@ public function from($table) { /** * Generates the JOIN portion of the query * + * @since 2.0.1 Changed all variable names and switched to meaningful array-keys + * * @param string $table * @param string $cond * @param string $type @@ -156,9 +164,9 @@ public function from($table) { public function join($table, $cond, $type = null, $escape = null) { - $this->joins[] = array('table' => $table, - 'cond' => $cond, - 'type' => $type, + $this->joins[] = array('table' => $table, + 'cond' => $cond, + 'type' => $type, 'escape' => $escape); $this->ci->db->join($table, $cond, $type, $escape); @@ -170,6 +178,8 @@ public function join($table, $cond, $type = null, $escape = null) { /** * Generates the WHERE portion of the query * + * @since 2.0.1 Changed all variable names and switched to meaningful array-keys + * * @param mixed $key * @param string $value * @param bool $escape @@ -179,9 +189,9 @@ public function join($table, $cond, $type = null, $escape = null) { public function where($key, $value = null, $escape = true) { $this->where[] = array('key' => $key, - 'value' => $value, + 'value' => $value, 'escape' => $escape); - + $this->ci->db->where($key, $value, $escape); return $this; @@ -200,9 +210,9 @@ public function where($key, $value = null, $escape = true) { public function or_where($key, $value = null, $escape = true) { $this->or_where[] = array('key' => $key, - 'value' => $value, + 'value' => $value, 'escape' => $escape); - + $this->ci->db->or_where($key, $value, $escape); return $this; @@ -212,6 +222,8 @@ public function or_where($key, $value = null, $escape = true) { /** * Generates the WHERE IN portion of the query * + * @since 2.0.1 Changed all variable names and switched to meaningful array-keys + * * @param mixed $key * @param string $value * @param bool $escape @@ -221,9 +233,9 @@ public function or_where($key, $value = null, $escape = true) { public function where_in($key, $value = null, $escape = true) { $this->where_in[] = array('key' => $key, - 'value' => $value, + 'value' => $value, 'escape' => $escape); - + $this->ci->db->where_in($key, $value, $escape); return $this; @@ -233,6 +245,8 @@ public function where_in($key, $value = null, $escape = true) { /** * Generates the WHERE portion of the query * + * @since 2.0.1 Changed all variable names and switched to meaningful array-keys + * * @param mixed $key * @param string $value * @param bool $escape @@ -242,7 +256,7 @@ public function where_in($key, $value = null, $escape = true) { public function filter($key, $value = null, $escape = true) { $this->filter[] = array('key' => $key, - 'value' => $value, + 'value' => $value, 'escape' => $escape); return $this; @@ -252,6 +266,8 @@ public function filter($key, $value = null, $escape = true) { /** * Generates a %LIKE% portion of the query * + * @since 2.0.1 Changed all variable names and switched to meaningful array-keys + * * @param mixed $field * @param string $match * @param mixed $side @@ -261,11 +277,11 @@ public function filter($key, $value = null, $escape = true) { public function like($field, $match = '', $side = 'both', $escape = NULL) { - $this->like[] = array('field' => $field, - 'match' => $match, - 'side' => $side, + $this->like[] = array('field' => $field, + 'match' => $match, + 'side' => $side, 'escape' => $escape); - + $this->ci->db->like($field, $match, $side, $escape); return $this; @@ -275,6 +291,8 @@ public function like($field, $match = '', $side = 'both', $escape = NULL) { /** * Generates the OR %LIKE% portion of the query * + * @since 2.0.1 Changed all variable names and switched to meaningful array-keys + * * @param mixed $field * @param string $match * @param mixed $side @@ -284,11 +302,11 @@ public function like($field, $match = '', $side = 'both', $escape = NULL) { public function or_like($field, $match = '', $side = 'both', $escape = NULL) { - $this->or_like[] = array('field' => $field, - 'match' => $match, - 'side' => $side, + $this->or_like[] = array('field' => $field, + 'match' => $match, + 'side' => $side, 'escape' => $escape); - + $this->ci->db->or_like($field, $match, $side, $escape); return $this; @@ -298,6 +316,8 @@ public function or_like($field, $match = '', $side = 'both', $escape = NULL) { /** * Sets additional column variables for adding custom columns * + * @since 2.0.1 Changed all variable names and switched to meaningful array-keys + * * @param string $column * @param string $content * @param mixed $match_replacement @@ -340,7 +360,7 @@ public function edit_column($column, $content, $match_replacement) { public function unset_column($column) { - $column = array_flip(explode(',', $column)); // Issue #66, fix by ajindam + $column = array_flip(explode(',', $column)); // Issue #66, fix by ajindam $this->unset_columns = array_merge($this->unset_columns, $column); return $this; @@ -376,8 +396,8 @@ public function generate($output = 'json', $charset = 'UTF-8') { private function get_paging() { - $iStart = $this->ci->input->post('start'); - $iLength = $this->ci->input->post('length'); + $iStart = $this->ci->input->post('start'); + $iLength = $this->ci->input->post('length'); if ($iLength != '' && $iLength != '-1') { $this->ci->db->limit($iLength, ($iStart) ? $iStart : 0); @@ -393,7 +413,7 @@ private function get_paging() { private function get_ordering() { - $Data = $this->ci->input->post('columns'); + $Data = $this->ci->input->post('columns'); if ($this->ci->input->post('order')) { @@ -423,12 +443,13 @@ private function get_ordering() { private function get_filtering() { - $mColArray = $this->ci->input->post('columns'); + $mColArray = $this->ci->input->post('columns'); + + $sWhere = ''; + $search = $this->ci->input->post('search'); + $sSearch = $this->ci->db->escape_like_str(trim($search['value'])); - $sWhere = ''; - $search = $this->ci->input->post('search'); - $sSearch = $this->ci->db->escape_like_str(trim($search['value'])); - $columns = array_values(array_diff($this->columns, $this->unset_columns)); + $columns = array_values(array_diff($this->columns, $this->unset_columns)); if ($sSearch != '') { @@ -438,11 +459,11 @@ private function get_filtering() { if ($this->check_cType()) { - $sWhere .= $this->select[$mColArray[$i]['data']] . " LIKE '%" . $sSearch . "%' OR "; + $sWhere .= $this->select[$mColArray[$i]['data']]." LIKE '%".$sSearch."%' OR "; } else { - $sWhere .= $this->select[$this->columns[$i]] . " LIKE '%" . $sSearch . "%' OR "; + $sWhere .= $this->select[$this->columns[$i]]." LIKE '%".$sSearch."%' OR "; } @@ -452,10 +473,10 @@ private function get_filtering() { } - $sWhere = substr_replace($sWhere, '', -3); + $sWhere = substr_replace($sWhere, '', -3); if ($sWhere != '') { - $this->ci->db->where('(' . $sWhere . ')'); + $this->ci->db->where('('.$sWhere.')'); } // TODO : sRangeSeparator @@ -469,18 +490,22 @@ private function get_filtering() { /** * Compiles the select statement based on the other functions called and runs the query * + * @since 2.0.1 Removed table-name because of issue #78, fix by oobi + * * @return mixed */ private function get_display_result() { - return $this->ci->db->get(); // Issue #78, fix by oobi + return $this->ci->db->get(); } /** * Builds an encoded string data. Returns JSON by default, and an array of aaData if output is set to raw. * + * @since 2.0.1 output and charset are now only "sanitized" in this function and nowhere else + * * @param string $output * @param string $charset * @return mixed @@ -494,10 +519,10 @@ private function produce_output($output, $charset) { $rResult = $this->get_display_result(); if ($output == 'json') { - + $iTotal = $this->get_total_results(); $iFilteredTotal = $this->get_total_results(true); - + } foreach ($rResult->result_array() as $row_key => $row_val) { @@ -541,10 +566,10 @@ private function produce_output($output, $charset) { if ($output == 'json') { - $sOutput = array('draw' => intval($this->ci->input->post('draw')), - 'recordsTotal' => $iTotal, - 'recordsFiltered' => $iFilteredTotal, - 'data' => $aaData ); + $sOutput = array('draw' => intval($this->ci->input->post('draw')), + 'recordsTotal' => $iTotal, + 'recordsFiltered' => $iFilteredTotal, + 'data' => $aaData ); if ($charset == 'utf-8') { return json_encode($sOutput); @@ -575,7 +600,7 @@ private function get_total_results($filtering = false) { // Set FROM early so table aliases are respected - Issue #78, fix by oobi $this->ci->db->from($this->table); - + foreach ($this->joins as $val) { $this->ci->db->join($val['table'], $val['cond'], $val['type'], $val['escape']); } @@ -645,7 +670,7 @@ private function exec_replace($custom_val, $row_data) { $args = preg_split("/[\s,]*\\\"([^\\\"]+)\\\"[\s,]*|" . "[\s,]*'([^']+)'[\s,]*|" . "[,]+/", $matches[2], 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); foreach ($args as $args_key => $args_val) { - + $args_val = preg_replace("/(?columns)) ? ($row_data[($this->check_cType()) ? $args_val : array_search($args_val, $this->columns)]) : $args_val; @@ -674,19 +699,30 @@ private function exec_replace($custom_val, $row_data) { } /** - * Check column type -numeric or column name + * Check column type -> numeric or column name + * + * @since 2.0.1 Added caching to $column to prevent calling CodeIgniter's XSS-protection over and over + * @since 2.0.0 * * @return bool */ private function check_cType() { - $column = $this->ci->input->post('columns'); + static $column; + + if (is_null($column)) { + $column = $this->ci->input->post('columns'); + } if (is_numeric($column[0]['data'])) { + return false; + } else { + return true; + } } @@ -694,18 +730,18 @@ private function check_cType() { /** * Return the difference of open and close characters * - * @param string $str - * @param string $open - * @param string $close - * @return string $retval + * @param string $str + * @param string $open + * @param string $close + * @return int $retval */ private function balanceChars($str, $open, $close) { - $openCount = substr_count($str, $open); - $closeCount = substr_count($str, $close); + $openCount = substr_count($str, $open); + $closeCount = substr_count($str, $close); - $retval = $openCount - $closeCount; + $retval = $openCount - $closeCount; return $retval; @@ -714,36 +750,38 @@ private function balanceChars($str, $open, $close) { /** * Explode, but ignore delimiter until closing characters are found * - * @param string $delimiter - * @param string $str - * @param string $open - * @param string $close - * @return mixed $retval + * @param string $delimiter + * @param string $str + * @param string $open + * @param string $close + * @return mixed $retval */ private function explode($delimiter, $str, $open = '(', $close=')') { - $retval = array(); - $hold = array(); - $balance = 0; - $parts = explode($delimiter, $str); + $retval = array(); + $hold = array(); + $balance = 0; + $parts = explode($delimiter, $str); foreach ($parts as $part) { - $hold[] = $part; - $balance += $this->balanceChars($part, $open, $close); + $hold[] = $part; + $balance += $this->balanceChars($part, $open, $close); if ($balance < 1) { - $retval[] = implode($delimiter, $hold); - $hold = array(); - $balance = 0; + + $retval[] = implode($delimiter, $hold); + $hold = array(); + $balance = 0; + } } if (count($hold) > 0) { - $retval[] = implode($delimiter, $hold); + $retval[] = implode($delimiter, $hold); } @@ -754,7 +792,7 @@ private function explode($delimiter, $str, $open = '(', $close=')') { /** * Workaround for json_encode's UTF-8 encoding if a different charset needs to be used * - * @param mixed $result + * @param mixed $result * @return string */ @@ -775,14 +813,16 @@ private function jsonify($result = false) { if (is_scalar($result)) { if (is_float($result)) { + return floatval(str_replace(',', '.', strval($result))); + } if (is_string($result)) { - static $jsonReplaces = array(array('\\', '/', '\n', '\t', '\r', '\b', '\f', '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"')); + static $jsonReplaces = array(array('\\', '/', '\n', '\t', '\r', '\b', '\f', '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"')); - return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $result) . '"'; + return '"'.str_replace($jsonReplaces[0], $jsonReplaces[1], $result).'"'; } else { @@ -792,13 +832,13 @@ private function jsonify($result = false) { } - $isList = true; + $isList = true; - for ($i = 0, reset($result); $i < count($result); $i++, next($result)) { + for ($i=0, reset($result); $ijsonify($value); + + $json[] = $this->jsonify($value); + } - return '[' . join(',', $json) . ']'; + return '['.join(',', $json).']'; } else { foreach ($result as $key => $value) { - $json[] = $this->jsonify($key) . ':' . $this->jsonify($value); + + $json[] = $this->jsonify($key).':'.$this->jsonify($value); + } - return '{' . join(',', $json) . '}'; + return '{'.join(',', $json).'}'; } } /** - * returns the sql statement of the last query run - * @return type - */ + * Returns the sql statement of the last query run + * + * @return type + */ public function last_query() { - return $this->ci->db->last_query(); + return $this->ci->db->last_query(); } From fcedfa34b0addff88ddd1a664178920e79b3e5dd Mon Sep 17 00:00:00 2001 From: Christian Land Date: Fri, 13 Oct 2017 15:43:54 +0200 Subject: [PATCH 06/10] Large Resultset performance/memory leak A first take on fixing the memory-leak/performance-issue when huge result-sets are queried. --- application/libraries/Datatables.php | 51 +++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/application/libraries/Datatables.php b/application/libraries/Datatables.php index 74d3d3d..b257723 100644 --- a/application/libraries/Datatables.php +++ b/application/libraries/Datatables.php @@ -28,6 +28,7 @@ class Datatables { private $ci; private $table; private $distinct; + private $count_column; private $group_by = array(); private $select = array(); private $joins = array(); @@ -313,6 +314,21 @@ public function or_like($field, $match = '', $side = 'both', $escape = NULL) { } + /** + * Sets the column used for counting improving performance + * + * @param string $column + * @return mixed + */ + + public function set_count_column($column) { + + $this->count_column = $column; + + return $this; + + } + /** * Sets additional column variables for adding custom columns * @@ -588,6 +604,10 @@ private function produce_output($output, $charset) { /** * Get result count * + * @since 2.0.1 First attempt at fixing the poor performance for big tables. + * Takes some ideas from https://github.com/IgnitedDatatables/Ignited-Datatables/pull/122 and + * https://github.com/IgnitedDatatables/Ignited-Datatables/pull/94 + * * @param mixed $filtering * @return integer */ @@ -630,13 +650,36 @@ private function get_total_results($filtering = false) { } if (strlen($this->distinct) > 0) { + $this->ci->db->distinct($this->distinct); - $this->ci->db->select($this->columns); - } + $this->ci->db->select($this->select); + + } else { + + if (strlen($this->count_column) > 0) { + + $this->ci->db->select('COUNT('.$this->count_column.') AS num_rows'); + $query = $this->ci->db->get(null, null, null, false); + $res = $query->result(); + + return $res[0]->num_rows; + + } else { + + $this->ci->db->select($this->select); + + } - $query = $this->ci->db->get(null, null, null, false); - return $query->num_rows(); + } + + $subquery = $this->ci->db->get_compiled_select(); + $countingsql = "SELECT COUNT(*) FROM (" . $subquery . ") SqueryAux"; + $query = $this->ci->db->query($countingsql); + $result = $query->row_array(); + $count = $result['COUNT(*)']; + + return $count; } From 379be913060c1f1b149891ddd0e6773359e28635 Mon Sep 17 00:00:00 2001 From: Christian Land Date: Fri, 13 Oct 2017 16:18:07 +0200 Subject: [PATCH 07/10] Minor Performance Tweaks Changed the way recordsTota) and recordsFiltered are calculated. --- application/libraries/Datatables.php | 46 ++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/application/libraries/Datatables.php b/application/libraries/Datatables.php index b257723..2c16d81 100644 --- a/application/libraries/Datatables.php +++ b/application/libraries/Datatables.php @@ -29,6 +29,7 @@ class Datatables { private $table; private $distinct; private $count_column; + private $calc_total = false; private $group_by = array(); private $select = array(); private $joins = array(); @@ -53,6 +54,28 @@ public function __construct() { } + /** + * If calc_total is TRUE, the class queries the number of records twice. + * Once without filtering (recordsTotal) and once with filtering (recordsFiltered). + * Usually, recordsTotal is used to display something like "Showing 1 to 20 of 3000 entries (filtered from 10000 total entries)" + * If you aren't interested in the "(filtered from 10000 total entries)"-part, set calc_total to FALSE and it will set recordsTotal to + * the same value as recordsFiltered. + * + * Default is FALSE because it can have a huge negative performance impact if you set it to TRUE. + * + * @since 2.0.1 + * + * @param bool $calc_total + * @return mixed + */ + + public function set_calc_total($calc_total = false) { + + $this->calc_total = $calc_total; + return $this; + + } + /** * If you establish multiple databases in config/database.php this will allow you to * set the database (other than $active_group) - more info: https://www.codeigniter.com/userguide3/database/connecting.html#connecting-to-multiple-databases @@ -429,7 +452,7 @@ private function get_paging() { private function get_ordering() { - $Data = $this->ci->input->post('columns'); + $data = $this->ci->input->post('columns'); if ($this->ci->input->post('order')) { @@ -437,7 +460,7 @@ private function get_ordering() { if ($this->check_cType()) { - $this->ci->db->order_by($Data[$key['column']]['data'], $key['dir']); + $this->ci->db->order_by($data[$key['column']]['data'], $key['dir']); } else { @@ -528,6 +551,8 @@ private function get_display_result() { */ private function produce_output($output, $charset) { + + // Initialize Variables $aaData = array(); $output = trim(strtolower($output)); @@ -535,11 +560,20 @@ private function produce_output($output, $charset) { $rResult = $this->get_display_result(); if ($output == 'json') { + + // Count records if necessary - $iTotal = $this->get_total_results(); $iFilteredTotal = $this->get_total_results(true); + if ($this->calc_total === true) { + $iTotal = $this->get_total_results(); + } else { + $iTotal = $iFilteredTotal; + } + } + + // Process return-data foreach ($rResult->result_array() as $row_key => $row_val) { @@ -614,13 +648,13 @@ private function produce_output($output, $charset) { private function get_total_results($filtering = false) { + // Set FROM early so table aliases are respected - Issue #78, fix by oobi + $this->ci->db->from($this->table); + if ($filtering) { $this->get_filtering(); } - // Set FROM early so table aliases are respected - Issue #78, fix by oobi - $this->ci->db->from($this->table); - foreach ($this->joins as $val) { $this->ci->db->join($val['table'], $val['cond'], $val['type'], $val['escape']); } From d0af8acd40effbfcdcade70a462842bf42438395 Mon Sep 17 00:00:00 2001 From: Christian Land Date: Fri, 13 Oct 2017 20:08:48 +0200 Subject: [PATCH 08/10] New ReadMe --- readme.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ readme.txt | 54 ------------------------------------------------------ 2 files changed, 44 insertions(+), 54 deletions(-) create mode 100644 readme.md delete mode 100644 readme.txt diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..30962e5 --- /dev/null +++ b/readme.md @@ -0,0 +1,44 @@ +## Ignited Datatables + +**Ignited Datatables** is a wrapper class/library based on the [native Datatables server-side implementation by Allan Jardine](https://legacy.datatables.net/examples/data_sources/server_side.html) for CodeIgniter + +Fork: https://github.com/IgnitedDatatables/Ignited-Datatables +Wiki: https://github.com/IgnitedDatatables/Ignited-Datatables/wiki +Issues: https://github.com/IgnitedDatatables/Ignited-Datatables/issues +Contact: Vincent Bambico + Yusuf Ozdemir + +### Requirements + +jQuery 1.5+ +DataTables 1.10+ +CodeIgniter 3.0.0 + +### Install + +To install the library, copy the libraries/datatables.php file into your application/libraries folder. + +### License + +**DON'T BE A DICK PUBLIC LICENSE** + +Version 1, December 2009 + +Copyright (C) 2009 Philip Sturgeon +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. + +**DON'T BE A DICK PUBLIC LICENSE** +**TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION** + +* Do whatever you like with the original work, just don't be a dick. Being a dick includes - but is not limited to - the following instances: + * Outright copyright infringement - Don't just copy this and change the name. + * Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick. + * Modifying the original work to contain hidden harmful content. That would make you a PROPER dick. + +* If you become rich through modifications, related works/services, or supporting the original work, +share the love. Only a dick would make loads off this work and not buy the original works +creator(s) a pint. +* Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes +you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back. \ No newline at end of file diff --git a/readme.txt b/readme.txt deleted file mode 100644 index 2e7d63e..0000000 --- a/readme.txt +++ /dev/null @@ -1,54 +0,0 @@ -********************** -* Ignited Datatables * -********************** - -Ignited Datatables is a wrapper class/library based on the native Datatables server-side implementation by Allan Jardine -found at http://datatables.net/examples/data_sources/server_side.html for CodeIgniter - -Fork : https://github.com/IgnitedDatatables/Ignited-Datatables -Wiki : https://github.com/IgnitedDatatables/Ignited-Datatables/wiki -Discuss: http://ellislab.com/forums/viewthread/160896/ -Contact: Vincent Bambico - Yusuf Ozdemir - -============ -Requirements -============ -jQuery 1.5+ -DataTables 1.10+ -CodeIgniter "Reactor" - -======= -Install -======= -To install the library, copy the libraries/datatables.php file into your application/libraries folder. - -======= -License -======= -DON'T BE A DICK PUBLIC LICENSE - -Version 1, December 2009 - -Copyright (C) 2009 Philip Sturgeon -Everyone is permitted to copy and distribute verbatim or modified -copies of this license document, and changing it is allowed as long -as the name is changed. - -DON'T BE A DICK PUBLIC LICENSE -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -1. Do whatever you like with the original work, just don't be a dick. - -Being a dick includes - but is not limited to - the following instances: - -1a. Outright copyright infringement - Don't just copy this and change the name. -1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick. -1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick. - -2. If you become rich through modifications, related works/services, or supporting the original work, -share the love. Only a dick would make loads off this work and not buy the original works -creator(s) a pint. - -3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes -you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back. From 0c4af11b16109c0f0279c2ab421c2160736a05ee Mon Sep 17 00:00:00 2001 From: Christian Land Date: Fri, 13 Oct 2017 20:15:20 +0200 Subject: [PATCH 09/10] Updated ReadMe (again) Yeah, formatting was borked due to Githubs way of using Markdown. --- readme.md | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/readme.md b/readme.md index 30962e5..8046629 100644 --- a/readme.md +++ b/readme.md @@ -1,24 +1,23 @@ -## Ignited Datatables +# Ignited Datatables -**Ignited Datatables** is a wrapper class/library based on the [native Datatables server-side implementation by Allan Jardine](https://legacy.datatables.net/examples/data_sources/server_side.html) for CodeIgniter +**Ignited Datatables** is a wrapper class/library based on the [native Datatables server-side implementation by Allan Jardine](https://legacy.datatables.net/examples/data_sources/server_side.html) for CodeIgniter. -Fork: https://github.com/IgnitedDatatables/Ignited-Datatables -Wiki: https://github.com/IgnitedDatatables/Ignited-Datatables/wiki -Issues: https://github.com/IgnitedDatatables/Ignited-Datatables/issues -Contact: Vincent Bambico - Yusuf Ozdemir +* Fork: https://github.com/IgnitedDatatables/Ignited-Datatables +* Wiki: https://github.com/IgnitedDatatables/Ignited-Datatables/wiki +* Issues: https://github.com/IgnitedDatatables/Ignited-Datatables/issues +* Contact: Vincent Bambico , Yusuf Ozdemir -### Requirements +## Requirements -jQuery 1.5+ -DataTables 1.10+ -CodeIgniter 3.0.0 +* jQuery 1.5+ +* DataTables 1.10+ +* CodeIgniter 3.0.0 -### Install +## Install -To install the library, copy the libraries/datatables.php file into your application/libraries folder. +To install the library, copy the `libraries/Datatables.php` file into your `application/libraries` folder. -### License +## License **DON'T BE A DICK PUBLIC LICENSE** @@ -33,12 +32,15 @@ as the name is changed. **TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION** * Do whatever you like with the original work, just don't be a dick. Being a dick includes - but is not limited to - the following instances: - * Outright copyright infringement - Don't just copy this and change the name. - * Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick. - * Modifying the original work to contain hidden harmful content. That would make you a PROPER dick. + + * Outright copyright infringement - Don't just copy this and change the name. + * Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick. + * Modifying the original work to contain hidden harmful content. That would make you a PROPER dick. * If you become rich through modifications, related works/services, or supporting the original work, share the love. Only a dick would make loads off this work and not buy the original works creator(s) a pint. + + * Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back. \ No newline at end of file From a29968e82aaeb61bd90ffbec56bf4b46db3b2e5a Mon Sep 17 00:00:00 2001 From: Christian Land Date: Thu, 19 Oct 2017 15:42:23 +0200 Subject: [PATCH 10/10] Another change to get_total_results Modified the way get_total_results() decides which fields to use in SELECT --- application/libraries/Datatables.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/application/libraries/Datatables.php b/application/libraries/Datatables.php index 2c16d81..ae3af56 100644 --- a/application/libraries/Datatables.php +++ b/application/libraries/Datatables.php @@ -43,6 +43,7 @@ class Datatables { private $add_columns = array(); private $edit_columns = array(); private $unset_columns = array(); + private $oselect = ''; /** * Copies an instance of CI @@ -114,6 +115,7 @@ public function select($columns, $escape = true) { } $this->ci->db->select($columns, $escape); + $this->oselect = $columns; return $this; @@ -593,7 +595,6 @@ private function produce_output($output, $charset) { } - foreach ($this->edit_columns as $modkey => $modval) { foreach ($modval as $val) { @@ -686,7 +687,7 @@ private function get_total_results($filtering = false) { if (strlen($this->distinct) > 0) { $this->ci->db->distinct($this->distinct); - $this->ci->db->select($this->select); + $this->ci->db->select($this->oselect); } else { @@ -700,7 +701,7 @@ private function get_total_results($filtering = false) { } else { - $this->ci->db->select($this->select); + $this->ci->db->select($this->oselect); } @@ -964,4 +965,4 @@ public function last_query() { } /* End of file Datatables.php */ -/* Location: ./application/libraries/Datatables.php */ +/* Location: ./application/libraries/Datatables.php */ \ No newline at end of file