app = $app; $this->config = $config; $this->dao = $app->dao; $this->cache = $app->cache; $this->reset(); } /** * 设置$table属性。 * Set the $table property. * * @param string $table * @access public * @return void */ public function setTable($table) { $this->table = $table; } /** * 设置$fields属性。 * Set the $fields property. * * @param array $fields * @access public * @return void */ public function setFields($fields) { $this->fields = $fields; } /** * 设置条件。 * Set the $conditions property. * * @param array $conditions * @access public * @return void */ public function setConditions($conditions) { $this->conditions = $conditions; $this->resetCondition(); } /** * 重置组装条件。 * Reset the $condition property. * * @access public * @return void */ public function resetCondition() { $this->condition = array('field' => '', 'operator' => '', 'value' => null); } /** * 添加条件。 * Add the $conditions property. * * @param string $condition * @access public * @return void */ public function addCondition() { $this->conditions[] = $this->condition; } /** * 重置属性。 * Reset the vars. * * @access public * @return void */ public function reset() { $this->setFields(array()); $this->setTable(''); $this->setConditions([]); } /** * select方法,调用sql::select()。 * The select method, call sql::select(). * * @param string $fields * @access public * @return static|sql|baseDAO the dao object self. */ public function select($fields = '*') { $this->conditions = []; $fields = explode(',', $fields); $alias = []; foreach($fields as $field) { $fieldInfo = explode(' ', trim($field)); if(count($fieldInfo) == 1) { $alias[$fieldInfo[0]] = $fieldInfo[0]; } elseif(count($fieldInfo) == 2) { $alias[$fieldInfo[0]] = $fieldInfo[1]; } else { $alias[$fieldInfo[0]] = $fieldInfo[2]; } } $this->setFields($alias); return $this; } /** * 设置要操作的表。 * Set the from table. * * @param string $tableName * @access public * @return static|sql the dao object self. */ public function from($tableName) { $this->setTable($tableName); return $this; } /** * 开始条件判断。 * Begin condition judge. * * @param bool|string $condition * @access public * @return static|sql the sql object. * @param bool|string $conditionResult */ public function beginIF($conditionResult) { $this->isConditionChecking = true; $this->conditionIsTrue = (bool)$conditionResult; return $this; } /** * 结束条件判断。 * End the condition judge. * * @access public * @return static|sql the sql object. */ public function fi() { $this->isConditionChecking = false; if(!$this->conditionIsTrue) { $this->resetCondition(); return $this; } $this->addCondition(); $this->resetCondition(); return $this; } /** * 创建WHERE部分。 * Create the where part. * * @param string $field the field name * @access public * @return static the dao object. */ public function where($field) { $this->resetCondition(); $this->condition['field'] = trim($field, '`'); return $this; } /** * 创建andWHERE部分。 * Create the andWhere part. * * @param string $field the field name * @access public * @return static the dao object. */ public function andWhere($field) { $this->resetCondition(); $this->condition['field'] = trim($field, '`'); return $this; } /** * 创建eq部分。 * Create the eq part. * * @param string $value * @access public * @return static the dao object. */ public function eq($value) { $this->condition['operator'] = 'eq'; $this->condition['value'] = $value; if(!$this->isConditionChecking) { $this->addCondition(); $this->resetCondition(); } return $this; } /** * 创建ne部分。 * Create the ne part. * * @param string $value * @access public * @return static the dao object. */ public function ne($value) { $this->condition['operator'] = 'ne'; $this->condition['value'] = $value; if(!$this->isConditionChecking) { $this->addCondition(); $this->resetCondition(); } return $this; } /** * 创建in部分。 * Create the in part. * * @param string|array $value * @access public * @return static the dao object. */ public function in($value) { $this->condition['operator'] = 'in'; $this->condition['value'] = is_string($value) ? explode(',', str_replace(' ', '', $value)) : $value; if(!$this->isConditionChecking) { $this->addCondition(); $this->resetCondition(); } return $this; } /** * 创建notin部分。 * Create the in part. * * @param string|array $value * @access public * @return static the dao object. */ public function notin($value) { $this->condition['operator'] = 'notin'; $this->condition['value'] = is_string($value) ? explode(',', str_replace(' ', '', $value)) : $value; if(!$this->isConditionChecking) { $this->addCondition(); $this->resetCondition(); } return $this; } /** * 判断匹配条件。 * Check condition is matched. * * @param object $object * @param array $conditions * @access public * @return bool */ private function isConditionMatched($object, $conditions) { foreach($conditions as $condition) { $value = $object->{$condition['field']}; if($condition['operator'] == 'eq') { if($condition['value'] != $value) return false; } elseif($condition['operator'] == 'ne') { if($condition['value'] == $value) return false; } elseif($condition['operator'] == 'in') { if(!in_array($value, $condition['value'])) return false; } elseif($condition['operator'] == 'notin') { if(in_array($value, $condition['value'])) return false; } else { return false; } } return true; } /** * 获取一个记录。 * Fetch one record. * * @param string $keyField 如果已经设置获取的字段,则只返回这个字段的值,否则返回这个记录。 * if the field is set, only return the value of this field, else return this record * @access public * @return object|mixed */ public function fetch($keyField = '') { if(empty($this->cache) || empty($this->config->cache->raw[$this->table]) || empty($this->conditions)) return $this->fetchFromDB('fetch', $keyField); $rawResult = null; /* 如果查询条件中有主键字段,则尝试通过主键字段从缓存中获取数据。If the query condition contains the primary key field, try to get data from the cache by the primary key field. */ $field = $this->config->cache->raw[$this->table]; foreach($this->conditions as $condition) { if($condition['field'] == $field && $condition['operator'] == 'eq') { $rawResult = $this->cache->fetch($this->table, $condition['value']); if($rawResult) { $keyField = trim($keyField, '`'); return $keyField ? $rawResult->$keyField : $rawResult; } break; } } return $this->fetchFromDB('fetch', $keyField); } /** * 获取所有记录。 * Fetch all records. * * @param string $keyField 返回以该字段做键的记录 * the key field, thus the return records is keyed by this field * @access public * @return array the records */ public function fetchAll($keyField = '') { if(empty($this->cache) || empty($this->config->cache->raw[$this->table]) || empty($this->conditions)) return $this->fetchFromDB('fetchAll', $keyField, false); $rawResult = null; /* 如果查询条件匹配到主键字段,则通过主键字段从缓存中获取数据。If the query condition matches the primary key field, get data from the cache by the primary key field. */ $field = $this->config->cache->raw[$this->table]; foreach($this->conditions as $condition) { if($condition['field'] == $field && $condition['operator'] == 'in') { $value = $condition['value']; if(is_numeric($value)) $value = [$value]; if(is_string($value)) $value = explode(',', str_replace(' ', '', $value)); if(is_array($value)) { $rawResult = $this->cache->fetchAll($this->table, array_filter($value)); foreach($rawResult as $index => $row) { /* 根据主键字段获取数据后,需要逐一匹配查询条件。After getting the data according to the primary key field, you need to match the query conditions one by one. */ if(!$this->isConditionMatched($row, $this->conditions)) unset($rawResult[$index]); } break; } } } /* 如果查询条件没有匹配到主键字段,则从计算结果缓存中获取数据。If the query condition does not match the primary key field, get data from the calculated result cache. */ //if(is_null($rawResult)) $rawResult = $this->cache->fetchAutoCache($this->table, $this->conditions); /* 如果没有缓存,从数据库中获取数据。If there is no cache, get data from the database. */ if(is_null($rawResult)) return $this->fetchFromDB('fetchAll', $keyField, false); if(!$rawResult) return []; /* 从缓存中获取到的是原始数据,需要根据查询字段和索引字段进行处理。The data obtained from the cache is raw data, which needs to be processed according to the query fields and index fields. */ $result = []; foreach($rawResult as $row) { $data = new stdclass(); foreach($this->fields as $field => $alias) { if($field == '*') { $data = $row; break; } $data->$alias = $row->$field; } empty($keyField) ? $result[] = $data : $result[$row->$keyField] = $data; } return $result; } /** * 获取的记录是以关联数组的形式 * Fetch array like key=>value. * * 如果没有设置参数,用首末两键作为参数。 * If the keyFiled and valueField not set, use the first and last in the record. * * @param string $keyField * @param string $valueField * @access public * @return array */ public function fetchPairs($keyField = '', $valueField = '') { if(empty($this->cache) || empty($this->config->cache->raw[$this->table])) return $this->fetchFromDB('fetchPairs', $keyField, $valueField); $rows = $this->fetchAll(); if(empty($rows)) return []; if(empty($keyField)) $keyField = $this->fields[0]; if(empty($valueField)) $valueField = $this->fields[1]; $pairs = []; foreach($rows as $row) { $pairs[$row->$keyField] = $row->$valueField; } return $pairs; } /** * 从数据库中获取数据。 * Fetch data from database. * * @param string $fetchFunc fetch|fetchAll * @param string $keyField * @param string|bool $valueField * @access private * @return mixed */ private function fetchFromDB($fetchFunc, $keyField, $valueField = '') { $fields = implode(',', $this->fields); $this->dao->select($fields)->from($this->table)->where('1=1'); foreach($this->conditions as $condition) { $func = $condition['operator']; $this->dao->andWhere($condition['field'])->$func($condition['value']); } return $this->dao->$fetchFunc($keyField, $valueField); } /** * 把名为 findByXXX 的方法转换为 where 条件。 * Convert the method findByXXX to where condition. * * @param string $method * @param array $args * @access private * @return object the mao object. */ private function findBy($method, $args) { $field = str_replace('findby', '', $method); if(count($args) == 1) { $operator = 'eq'; $value = $args[0]; } else { $operator = $args[0]; $value = $args[1]; } $this->setFields(['*']); $this->conditions = [['field' => $field, 'operator' => $operator, 'value' => $value]]; return $this; } /** * 获取缓存数据拼接到已有数据。 * Append cache fields to data. * * @param array $data * @param string $keyField * @access public * @return void */ public function into($data, $keyField) { if(empty($data) || empty($keyField)) return $data; /* Get data keys as conditions. */ $keyList = []; foreach($data as $index => $row) $keyList[$index] = $row->$keyField; if(empty($this->cache)) { /* 如果缓存关闭,从数据库中获取。If the cache is off, get from the database. */ $primaryKey = $this->config->cache->raw[$this->table]; $fields = $primaryKey . ',' . implode(',', array_keys($this->fields)); $cacheResult = $this->dao->select($fields)->from($this->table)->where($primaryKey)->in(array_unique($keyList))->fetchAll($primaryKey); } else { $cacheResult = $this->cache->fetchAll($this->table, array_unique($keyList)); } foreach($data as $index => $row) { $key = $keyList[$index]; if(isset($cacheResult[$key])) { $cacheRow = $cacheResult[$key]; foreach($this->fields as $field => $alias) $row->$alias = $cacheRow->$field; } else { foreach($this->fields as $field => $alias) $row->$alias = ''; } } } /** * 清除缓存。 * Clear cache. * * @access public * @return void */ public function clearCache() { if(!empty($this->cache)) $this->cache->clear(); } /** * 根据当前缓存键获取缓存。 * Get cache according to the current cache key. * * @access public * @return mixed */ public function get() { if(empty($this->cache)) return false; return $this->cache->get(); } /** * 魔术方法。 * 1. 转换 findByxxx 为 where 条件。 * 2. 调用cache对象的方法。 * Magic method. * 1. Convert findByxxx to where condition. * 2. Call the cache object method. * * @param string $method * @param array $args * @access public * @return mixed */ public function __call($method, $args) { $method = strtolower($method); /* * 如果是findByxxx,转换为where条件语句。 * findByxxx, xxx as will be in the where. **/ if(strpos($method, 'findby') !== false) return $this->findBy($method, $args); if(empty($this->cache)) return $this; if(method_exists($this->cache, $method)) return call_user_func_array([$this->cache, $method], $args); $this->app->triggerError("Method $method not found in class baseMao.", __FILE__, __LINE__, $this->config->debug >= 2); } }