classs('validator'); $this->query = load()->object('Query'); $this->query->fixTable = $this->tableName; $this->query->from($this->tableName); } public function searchWithPage($pageindex, $pagesize) { if (!empty($pageindex) && !empty($pagesize)) { $this->query->page($pageindex, $pagesize); } return $this; } public function getLastQueryTotal() { return $this->query->getLastQueryTotal(); } public function count() { return $this->query->count(); } public function fill($field, $value = '') { if (is_array($field)) { foreach ($field as $column => $val) { $this->fillField($column, $val); } return $this; } $this->fillField($field, $value); return $this; } private function fillField($column, $val) { if (in_array($column, $this->field)) { $val = $this->getColumnVal($column, $val); $this->attribute[$column] = $val; $this->query->fill($column, $val); } } private function getColumnVal($column, $val) { $method = 'set'.$this->studly($column).'Field'; if (method_exists($this, $method)) { return $this->{$method}($val); } return $this->cast($column, $val); } private function cast($column, $val) { if (isset($this->cast[$column])) { switch ($this->cast[$column]) { case 'int' : return intval($val); break; case 'string' : return strval($val); break; case 'float' : return floatval($val); break; case 'double' : return doubleval($val); break; case 'bool' : return boolval($val); break; } } return $val; } private function appendDefault() { foreach ($this->default as $field => $value) { if (! isset($this->attribute[$field])) { if ($value === 'custom') { $method = 'default'.$this->studly($field); if (! method_exists($this, $method)) { trigger_error($method.'方法未找到'); } $value = call_user_func(array($this, $method)); } $this->fillField($field, $value); } } } protected function valid($data) { if (count($this->rule) <= 0) { return error(0); } $validator = Validator::create($data, $this->rule); $result = $validator->valid(); return $result; } public function get() { $data = $this->query->get(); if (! $data || empty($data)) { return $data; } $this->loadRelation($data); return $data; } public function getall($keyfield = '') { $data = $this->query->getall($keyfield); if (! $data || empty($data)) { return $data; } $this->loadRelation($data, true); return $data; } public function getQuery() { return $this->query; } public function getTableName() { return $this->tableName; } public function with($relation) { $relations = is_string($relation) ? func_get_args() : $relation; foreach ($relations as $relation =>$val) { if (is_numeric($relation)) { $relation = $val; } if (!is_callable($val)) { $val = null; } $this->relationDefine[$relation] = $val; } return $this; } private function loadRelation(array &$data, $muti = false) { foreach ($this->relationDefine as $relation => $closure) { $this->doload($relation, $data, $muti, $closure); } } private function doload($relation, &$data, $muti = false, callable $closure = null) { if (method_exists($this, $relation)) { $relation_param = call_user_func(array($this, $relation)); list($type, $table, $foreign_key, $owner_key) = $relation_param; if ($type == self::MANY_TO_MANY) { $this->doManyToMany($relation, $relation_param, $data, $muti); return; } $single = $this->isGetSingle($type); $foreign_vals = $this->getForeignVal($data, $owner_key, $muti); $second_table_data = $this->getSecondTableData($table, $foreign_key, $foreign_vals, $single, $closure); if (! $muti) { $data[$relation] = $second_table_data; return; } if ($single) { $second_table_data = array($second_table_data); } $second_table_data = $this->groupBy($foreign_key, $second_table_data); foreach ($data as &$item) { $relation_val = isset($second_table_data[$item[$owner_key]]) ? $second_table_data[$item[$owner_key]] : array(); if ($single) { $relation_val = count($relation_val) > 0 ? current($relation_val) : array(); } $item[$relation] = $relation_val; } } } private function doManyToMany($relation, $relation_param, &$data, $muti = false) { list($type, $table, $foreign_key, $owner_key, $center_table, $center_foreign_key, $center_owner_key) = $relation_param; $foreign_vals = $this->getForeignVal($data, $owner_key, $muti); $three_table = table($table); $nativeQuery = $three_table->getQuery(); $nativeQuery->from($three_table->getTableName(), 'three') ->innerjoin($center_table, 'center') ->on(array('center.'.$center_foreign_key => 'three.'.$foreign_key)) ->select('center.*') ->where('center.'.$center_owner_key, $foreign_vals); $three_table_data = $three_table->getall(); if (!$muti) { $data[$relation] = $three_table_data; return; } $three_table_data = $this->groupBy($center_owner_key, $three_table_data); foreach ($data as &$item) { $three_val = isset($three_table_data[$item[$owner_key]]) ? $three_table_data[$item[$owner_key]] : array(); $item[$relation] = $three_val; } } private function isGetSingle($type) { return in_array($type, array(self::ONE_TO_ONE, self::BELONGS_TO)) ? true : false; } private function getForeignVal($data, $owner_key, $muti = false) { if (! $muti) { return $data[$owner_key]; } return array_map(function($item) use ($owner_key){ return $item[$owner_key]; }, $data); } private function getSecondTableData($table, $foreign_key, $foreign_vals, $single = false, $closure = null) { $table_instance = table($table)->where($foreign_key, $foreign_vals); if ($closure) { call_user_func($closure, $table_instance->getQuery()); } if ($single) { return $table_instance->get(); } return $table_instance->getall(); } private function groupBy($key, $array) { $result = array(); foreach ($array as $item) { $val = $item[$key]; if (isset($result[$val])) { $result[$val][] = $item; } else { $result[$val] = array($item); } } return $result; } protected function hasOne($table, $foreign_key, $owner_key = false) { return $this->relationArray(self::ONE_TO_ONE, $table, $foreign_key, $owner_key); } protected function hasMany($table, $foreign_key, $owner_key = false) { return $this->relationArray(self::ONE_TO_MANY, $table, $foreign_key, $owner_key); } protected function belongsTo($table, $foreign_key, $owner_key = false) { return $this->relationArray(self::BELONGS_TO, $table, $foreign_key, $owner_key); } protected function belongsMany($table, $foreign_key, $owner_key, $center_table, $center_foreign_key = false, $center_owner_key = false) { if (! $owner_key) { $owner_key = $this->primaryKey; } if (!$center_foreign_key) { $center_foreign_key = $foreign_key; } if (!$center_owner_key) { $center_owner_key = $owner_key; } return array(self::MANY_TO_MANY, $table, $foreign_key, $owner_key, $center_table, $center_foreign_key, $center_owner_key); } private function relationArray($type, $table, $foreign_key, $owner_key) { if (! $owner_key) { $owner_key = $this->primaryKey; } if (!in_array($type, array(self::ONE_TO_ONE, self::ONE_TO_MANY, self::BELONGS_TO), true)) { trigger_error('不支持的关联类型'); } return array($type, $table, $foreign_key, $owner_key); } public function getById($id) { $this->query->from($this->tableName)->where($this->primaryKey, $id); if (is_array($id)) { return $this->getall(); } return $this->get(); } public function getcolumn($field = '') { $data = $this->query->getcolumn($field); return $data; } public function where($condition, $parameters = array(), $operator = 'AND') { $this->query->where($condition, $parameters, $operator); return $this; } public function whereor($condition, $parameters = array()) { return $this->where($condition, $parameters, 'OR'); } public function orderby($field, $direction = 'ASC') { return $this->query->orderby($field, $direction); } public function save() { if($this->query->hasWhere()) { $result = $this->valid($this->attribute); if (is_error($result)) { return $result; } return $this->query->update(); } $this->appendDefault(); $result = $this->valid($this->attribute); if (is_error($result)) { return $result; } return $this->query->insert(); } public function delete() { if ($this->query->hasWhere()) { return $this->query->delete(); } return false; } private function doWhere($field, $params, $operator = 'AND') { if ($params == 0) { return $this; } $value = $params[0]; if (count($params) > 1) { $field = $field.' '.$params[1]; } $this->query->where($field, $value, $operator); return $this; } private function snake($value) { $delimiter = '_'; if (! ctype_lower($value)) { $value = preg_replace('/\s+/u', '', ucwords($value)); $value = strtolower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value)); } return $value; } private function studly($value) { $value = ucwords(str_replace(array('-', '_'), ' ', $value)); return str_replace(' ', '', $value); } public function __call($method, $params) { $actions = array( 'searchWith', 'whereor', 'where', 'fill' ); foreach ($actions as $action) { $fields = explode($action, $method); if (count($fields) > 1 && empty($fields[0]) && !empty($fields[1])) { $field = $this->snake($fields[1]); switch ($action) { case 'whereor': return $this->doWhere($field, $params, 'OR'); case 'fill' : $this->fill($field, $params[0]); return $this; default : return $this->doWhere($field, $params); } } } return $this; } }