Model Trait for CI

<?php
//namespace App\Traits;

// To set $locale value of a model and translate all translatable attributes

/*
    usage:
    require_once APPPATH.'traits/ModelBasis.php';
 
    use ModelBasis;
 
    //Table name
    protected $table = 'table_name';

    //Timestamp column name
    protected $created_at = 'created_at';
    protected $updated_at = 'updated_at';
 
    public $err = '';
 
    //檢查欄位用,只需要輸入必填的欄位
    public $fields = [
        'name' => ['姓名', 'string'], 
        'account' => ['編號', 'string'], 
        'admin_group_id' => ['群組', 'string'], 
    ];
*/

trait ModelBasis
{
    function last_query(){
        return $this->db->last_query();
    }
    
    function get_created_at(){
        if(isset($this->created_at) == false){
            return 'created_at';
        }else{
            return $this->created_at;
        }
    }

    function get_updated_at(){
        if(isset($this->updated_at) == false){
            return 'updated_at';
        }else{
            return $this->updated_at;
        }
    }

    function all($order=null, $select="*"){
        if($order != false){
            foreach ($order as $key => $value) {
                $this->db->order_by($key, $value);
            }
        }

        $this->db->select($select);
        $query = $this->db->get($this->table);
        return $query->result();
    }

    function where($rules, $first=false, $order=null, $select="*"){
        if($order != false){
            foreach ($order as $key => $value) {
                $this->db->order_by($key, $value);
            }
        }

        //$array = array('name !=' => $name, 'id <' => $id, 'date >' => $date);
        $this->db->where($rules);

        $this->db->select($select);
        $query = $this->db->get($this->table);

        if($first == true){
            return $query->row();
        }
        
        return $query->result();
    }

    function find($id, $key_field_name="id", $columns='*')
    {
        $this->db->select($columns);
        $this->db->where($key_field_name, $id);
        $query = $this->db->get($this->table);
        //logg($this->db->last_query());
        if ($query->num_rows() == 0){
            return false;
        }else{
            $data = $query->row();
            return $data;
        }
    }

    function update_item($id, $data, $timestamp=true, $key_name="id")
    {
        if(is_array($data) == false){
            $data = (array)$data;
        }

        if($timestamp == true){
            //$data['updated_at'] = Carbon::now()->toDateTimeString();
            $updated_at = $this->get_updated_at();
            $data[$updated_at] = timestamp_string();
        }

        $this->db->where($key_name, $id);
        $query = $this->db->update($this->table, $data);
        //logg($this->db->last_query());
        return $query;
    }

    function new_item($data, $timestamp=true, $return_id=true)
    {
        if(is_array($data) == false){
            $data = (array)$data;
        }

        if($timestamp == true){
            $created_at = $this->get_created_at();
            $data[$created_at] = timestamp_string();
        }

        $query = $this->db->insert($this->table, $data);
        //logg($this->db->last_query());
        //logg($query);
        if($query == false){
            return false;
        }

        if($return_id == true){
            return $this->db->insert_id();
        }

        return true;
    }

    function new_items($data, $timestamp=true)
    {
        if($timestamp == true){
            $created_at = $this->get_created_at();

            foreach ($data as $key => $item) {
                $item[$created_at] = timestamp_string();
                $data[$key] = $item;
            }
        }

        $query = $this->db->insert_batch($this->table, $data);
        //logg($this->db->last_query());
        //logg($query);
        if($query == false){
            return false;
        }

        return true;
    }

    function delete_item($id, $key='id')
    {
        $this->db->where($key, $id);
        $query = $this->db->delete($this->table);
        return $query;
    }

    function truncate(){
        $this->db->truncate($this->table);
    }

    function fields(){
        return $this->db->field_data($this->table);
    }

    function field_names($table){
        return $this->db->list_fields($table);
    }

    public function find_value($col_name, $value){
        $this->db->where($col_name, $value);
        $query = $this->db->get($this->table);
        //logg($this->db->last_query());

        if($query == false || $query->num_rows() == 0){
            return false;
        }

        return $query->result();
    }

    //檢查table是否有某個名稱的欄位
    //為了檢查log table是否有changed_at欄位建立
    function table_has_column($table, $col_name){
        $fields = $this->db->list_fields($table);
        foreach($fields as $key => $item){
            if($item == $col_name){
                return true;
            }
        }
        return false;
    }

    function add_change_log($id, $editor=null, $del=false, $id_field="id"){
        $fields = $this->db->list_fields($this->table);
        foreach($fields as $key => $item){
            $fields[$key] = "`" . $item . "`";
        }

        $has_changed_at = $this->table_has_column($this->table . '_log', 'changed_at');
        
        //如果log table有changed_at欄位,就自動補上目前時間
        $column_str = implode(', ', $fields);
        $select_str = "*";

        if($editor != false){
            $select_str .= ", '" . $editor . "'";
            $column_str .= ", `editor`";
        }

        if($has_changed_at == true){
            $select_str .= ", '" . date('Y-m-d H:i:s', time()) . "'";
            $column_str .= ", `changed_at`";
        }
        //logg($column_str);

        $sql = "INSERT INTO `{$this->table}_log` ({$column_str}) 
                SELECT {$select_str}
                FROM `{$this->table}`
                WHERE {$id_field} = {$id}";
        $result = $this->db->query($sql);
        if ($result == false){
            return false;
        }

        //如果log table沒有incremental id欄位,insert_id()永遠只會傳回0
        //所以不可以用$result_id == false來判斷程式是否成功
        $result_id = $this->db->insert_id();
        //logg($this->db->last_query());
        if ($del == true) {
            $this->db->where('id', $id);
            $result = $this->db->delete($this->table);
            if($result == false){
                return false;
            }
        }

        return $result_id;
    }

    function update_change_log($log_id, $data){
        $data['change_time'] = timestamp_string();

        $this->db->where('change_id', $log_id);
        $query = $this->db->update('orders_change_log', $data);
        return $query;
    }

    function max_sort($order_field="sort_order"){
        $this->db->select_max($order_field);
        $query = $this->db->get($this->table);

        if($query == false){
            return 0;
        }else{
            $row = $query->row();
            return $row->sort_order;
        }
    }

    //檢查的欄位一定都是必填的
    function validate_fields($data=null, $method="post"){
        if(isset($this->fields) == false || $this->fields == false){
            $this->err = '沒有欄位設定';
            return false;
        }

        foreach($this->fields as $key => $item){
            if($data == false){
                if($method == 'post'){
                    $value = $this->input->post($key);
                }else{
                    $value = $this->input->get($key);
                }
            }else{
                $value = val($data, $key);
            }

            $result = true;
            switch($item[1]){
                case 'int':
                    if($value == false){
                        if($value !== 0){
                            $this->err = $item[0] . ' 格式不正確';
                            $result = false;
                        }
                    }else{
                        if(is_numeric($value) == false){
                            $this->err = $item[0] . ' 格式不正確';
                            $result = false;
                        }
                    }
                    
                    break;
                case 'string':
                    if($value == false && $value !== 0){
                        $this->err = '請輸入 ' . $item[0];
                        $result = false;
                    }
                    break;
                default:
                    if($value == false && $value !== 0){
                        $this->err = '請輸入 ' . $item[0];
                        $result = false;
                    }
            }

            if($result == false){
                return false;
            }
        }

        return true;
    }
}