|
@@ -1,25 +1,228 @@
|
|
|
<?php
|
|
|
namespace Qii\Driver\Entity;
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-use Qii\Driver\Response;
|
|
|
+use \Qii\Driver\Response;
|
|
|
|
|
|
class Base {
|
|
|
- public static $propertys;
|
|
|
+ /**
|
|
|
+ * 字段及值
|
|
|
+ *
|
|
|
+ * @var array $properties
|
|
|
+ */
|
|
|
+ public static $properties;
|
|
|
+ public static $config;
|
|
|
+ /**
|
|
|
+ * hooker for fields 查询字段/ where 查询条件 / order 排序 / cache 缓存
|
|
|
+ * @var array $hooker
|
|
|
+ */
|
|
|
+ private $hooker = [];
|
|
|
+ /**
|
|
|
+ * 默认过期时间
|
|
|
+ *
|
|
|
+ * @var int $defaultExpired
|
|
|
+ */
|
|
|
+ private $defaultExpired = 600;
|
|
|
+
|
|
|
public function __construct(){
|
|
|
}
|
|
|
- public function defaultFieldsValue(){}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 默认值,仅在新增数据的时候支持,更新不支持
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public function defaultFieldsValue(){
|
|
|
+ return array();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 返回 table 的名字,以便分库分表的时候指定使用
|
|
|
+ *
|
|
|
+ * @return mixed
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
public function getTable() {
|
|
|
throw new \Exception('请先设置需要保存的数据表');
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 返回使用的db信息
|
|
|
+ * set hooker for method
|
|
|
+ * 目前 where 和 order 及 fields 支持
|
|
|
+ * @param $key
|
|
|
+ * @param $hooker
|
|
|
+ * @param $args
|
|
|
+ * @return $this
|
|
|
+ */
|
|
|
+ protected function setHooker($key, $hooker, $args) {
|
|
|
+ $this->hooker[$key]['func'] = $hooker;
|
|
|
+ $this->hooker[$key]['args'] = $args;
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置where hooker
|
|
|
+ * @param object $hooker
|
|
|
+ * @return $this
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ final public function setWhereHooker($hooker, $args = null) {
|
|
|
+ $this->checkCallable($hooker);
|
|
|
+ $this->setHooker('where', $hooker, $args);
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 获取where条件
|
|
|
+ *
|
|
|
+ * @return array|mixed
|
|
|
+ */
|
|
|
+ public function getWhereHooker() {
|
|
|
+ $where = $this->properties();
|
|
|
+ if(isset($this->hooker['where']) && $this->hooker['where'] && is_callable($this->hooker['where']['func'])) {
|
|
|
+ $where = call_user_func($this->hooker['where']['func'], $this->properties(), $this->hooker['where']['args']);
|
|
|
+ }
|
|
|
+ return $where;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置order by hooker
|
|
|
+ * @param object $hooker
|
|
|
+ * @return $this
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ final public function setOrderHooker($hooker, $args = null) {
|
|
|
+ $this->checkCallable($hooker);
|
|
|
+ $this->setHooker('order', $hooker, $args);
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置 limit hooker
|
|
|
+ *
|
|
|
+ * @param object $hooker
|
|
|
+ * @return $this
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ final public function setLimitHooker($hooker, $args = null) {
|
|
|
+ $this->checkCallable($hooker);
|
|
|
+ $this->setHooker('limit', $hooker, $args);
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 获取limit
|
|
|
+ * @return int|mixed
|
|
|
+ */
|
|
|
+ final public function getLimitHooker() {
|
|
|
+ if(isset($this->hooker['limit']) && $this->hooker['limit'] && is_callable($this->hooker['limit']['func'])) {
|
|
|
+ return call_user_func($this->hooker['limit']['func'], [], $this->hooker['limit']['args']);
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置 cache hooker
|
|
|
+ *
|
|
|
+ * @param callable $hooker
|
|
|
+ * @param array| mixed $args
|
|
|
+ * @return $this
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ final public function setCacheHooker($hooker, $args = null) {
|
|
|
+ $this->checkCallable($hooker);
|
|
|
+ $this->setHooker('cache', $hooker, $args);
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取Cache Hooker
|
|
|
+ * @return mixed|null[]
|
|
|
+ */
|
|
|
+ final public function getCacheHooker() {
|
|
|
+ if(isset($this->hooker['cache']) && $this->hooker['cache'] && is_callable($this->hooker['cache']['func'])) {
|
|
|
+ return call_user_func($this->hooker['cache']['func'], [], $this->hooker['cache']['args']);
|
|
|
+ }
|
|
|
+ return [null, null, null];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 缓存设置
|
|
|
+ *
|
|
|
+ * @param array $config 缓存配置
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ final public function setCacheConfig($config) {
|
|
|
+ if(!is_array($config)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ self::$config['cache'] = $config;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取缓存的配置信息
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ final public function getCacheConfig() {
|
|
|
+ if(is_array(self::$config) && isset(self::$config['cache']) && is_array(self::$config['cache'])) {
|
|
|
+ return self::$config['cache'];
|
|
|
+ }
|
|
|
+ return array();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 如果hooker不可调用即抛出异常
|
|
|
+ *
|
|
|
+ * @param object $hooker
|
|
|
+ * @return void
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ private function checkCallable($hooker) {
|
|
|
+ if($hooker && !is_callable($hooker)) {
|
|
|
+ throw new \Exception('Hooker is uncallable');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 设置order by hooker
|
|
|
+ * @param object $hooker
|
|
|
+ * @return $this
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ final public function setQueryFieldsHooker($hooker, $args = null) {
|
|
|
+ if(!is_callable($hooker)) {
|
|
|
+ throw new \Exception('Hooker is un callable');
|
|
|
+ }
|
|
|
+ $this->setHooker('fields', $hooker, $args);
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通过field hooker返回查询的字段
|
|
|
*
|
|
|
+ * @return mixed|string
|
|
|
+ */
|
|
|
+ final public function getFieldsHooker() {
|
|
|
+ if(isset($this->hooker['fields']) && $this->hooker['fields'] && is_callable($this->hooker['fields']['func'])) {
|
|
|
+ return call_user_func($this->hooker['fields']['func'], [], $this->hooker['fields']['args']);
|
|
|
+ }
|
|
|
+ return '*';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取指定field的值
|
|
|
+ * @param string $field
|
|
|
* @return mixed
|
|
|
*/
|
|
|
- public function db() {
|
|
|
+ final public function getFieldVal($field) {
|
|
|
+ if(!preg_match('/^[a-zA-Z]/', $field)) {
|
|
|
+ throw new \Exception('Field is illegal');
|
|
|
+ }
|
|
|
+ $property = $this->entity()->convertToProperty($field);
|
|
|
+ return $this->{$property};
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 返回使用的db信息
|
|
|
+ *
|
|
|
+ * @return \Qii\Driver\Base
|
|
|
+ */
|
|
|
+ final public function db() {
|
|
|
return _loadClass('\Qii\Driver\Model');
|
|
|
}
|
|
|
|
|
@@ -27,7 +230,7 @@ class Base {
|
|
|
* 返回 entity 信息
|
|
|
* @return mixed
|
|
|
*/
|
|
|
- public function entity() {
|
|
|
+ final public function entity() {
|
|
|
return _loadClass('\Qii\Driver\Entity\Entity');
|
|
|
}
|
|
|
|
|
@@ -81,10 +284,30 @@ class Base {
|
|
|
}
|
|
|
return explode($separator, $string, $limit);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加数据验证字段
|
|
|
+ *
|
|
|
+ * $fields = [];
|
|
|
+ * return $this->valid($fields);
|
|
|
+ *
|
|
|
+ * @return mixed
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
public function validFieldsForAdd(){
|
|
|
throw new \Exception('请设置插入数据验证的字段,格式如:["Id", "Title"],Id和Title为entity的属性');
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新数据验证字段
|
|
|
+ *
|
|
|
+ * $fields = [];
|
|
|
+ * return $this->valid($fields);
|
|
|
+ *
|
|
|
+ * @return mixed
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
public function validFieldsForUpdate() {
|
|
|
throw new \Exception('请设置更新数据验证的字段,格式如:["Id", "Title"],Id和Title为entity的属性');
|
|
|
}
|
|
@@ -93,7 +316,7 @@ class Base {
|
|
|
*
|
|
|
* @return array
|
|
|
*/
|
|
|
- public function properties() {
|
|
|
+ final public function properties() {
|
|
|
$class = get_called_class();
|
|
|
$method = new \ReflectionClass($class);
|
|
|
$properties = $method->getproperties();
|
|
@@ -111,12 +334,33 @@ class Base {
|
|
|
return $fields;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 清除变量内容
|
|
|
+ * @return $this
|
|
|
+ */
|
|
|
+ final public function clear() {
|
|
|
+ $class = get_called_class();
|
|
|
+ $method = new \ReflectionClass($class);
|
|
|
+ $properties = $method->getproperties();
|
|
|
+ $fields = [];
|
|
|
+ foreach($properties as $property) {
|
|
|
+ if($property->isPublic()) {
|
|
|
+ $name = $property->getName();
|
|
|
+ if(!isset($this->$name)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $this->$name = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 获取默认值
|
|
|
*
|
|
|
* @return array
|
|
|
*/
|
|
|
- public function getDefaultValue() {
|
|
|
+ final public function getDefaultValue() {
|
|
|
$default = [];
|
|
|
$defaultValue = $this->defaultFieldsValue();
|
|
|
if(!$defaultValue || !is_array($defaultValue) || count($defaultValue) == 0) {
|
|
@@ -135,8 +379,8 @@ class Base {
|
|
|
* @return mixed
|
|
|
* @throws \Exception
|
|
|
*/
|
|
|
- public function count() {
|
|
|
- return $this->db()->fields(' COUNT(1) as count')->where($this->properties())->selectOne($this->getTable());
|
|
|
+ final public function count() {
|
|
|
+ return $this->db()->fields(' COUNT(1) as count')->where($this->getWhereHooker())->selectOne($this->getTable());
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -145,31 +389,31 @@ class Base {
|
|
|
* @param $key
|
|
|
* @return bool
|
|
|
*/
|
|
|
- public function hasProperty($key) {
|
|
|
+ final public function hasProperty($key) {
|
|
|
$class = get_called_class();
|
|
|
$key = $this->entity()->convertToProperty($key);
|
|
|
- if(isset(self::$propertys[$class])) {
|
|
|
- return isset(self::$propertys[$class][$key]);
|
|
|
+ if(isset(self::$properties[$class])) {
|
|
|
+ return isset(self::$properties[$class][$key]);
|
|
|
}
|
|
|
$method = new \ReflectionClass($class);
|
|
|
$properties = $method->getproperties();
|
|
|
- $fields = [];
|
|
|
+ $fields = array();
|
|
|
foreach($properties as $property) {
|
|
|
if($property->isPublic()) {
|
|
|
$name = $property->getName();
|
|
|
$fields[$name] = '';
|
|
|
}
|
|
|
}
|
|
|
- self::$propertys[$class] = $fields;
|
|
|
+ self::$properties[$class] = $fields;
|
|
|
return isset($fields[$key]);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* bind value
|
|
|
* @param $values
|
|
|
- * @return $this|false
|
|
|
+ * @return $this
|
|
|
*/
|
|
|
- public function bindValues($values) {
|
|
|
+ final public function bindValues($values) {
|
|
|
if(!is_array($values)) {
|
|
|
return $this;
|
|
|
}
|
|
@@ -181,17 +425,21 @@ class Base {
|
|
|
}
|
|
|
return $this;
|
|
|
}
|
|
|
-
|
|
|
/**
|
|
|
* 获取数据
|
|
|
*
|
|
|
- * @return mixed
|
|
|
+ * @return Object
|
|
|
* @throws \Exception
|
|
|
*/
|
|
|
- public function get() {
|
|
|
- $info = $this->db()->where($this->properties())->selectRow($this->getTable());
|
|
|
+ final public function get() {
|
|
|
$class = get_called_class();
|
|
|
$obj = new $class();
|
|
|
+ $response = $this->info();
|
|
|
+ if($response->isError()) {
|
|
|
+ return $obj;
|
|
|
+ }
|
|
|
+ $info = $response->getResult()['body'];
|
|
|
+
|
|
|
if(!$info) {
|
|
|
return $obj;
|
|
|
}
|
|
@@ -201,32 +449,48 @@ class Base {
|
|
|
}
|
|
|
return $obj;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+ /**
|
|
|
+ * 与get不同的这个返回的是Response
|
|
|
+ * @return mixed|\Qii\Driver\Qii\Driver\Response
|
|
|
+ */
|
|
|
+ final public function info() {
|
|
|
+ try{
|
|
|
+ $info = $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->selectRow($this->getTable());
|
|
|
+ return Response::Success(
|
|
|
+ static::class .'::'. __FUNCTION__,
|
|
|
+ ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '获取成功', 'body' => $info]]
|
|
|
+ );
|
|
|
+ }catch (\Exception $e) {
|
|
|
+ return Response::Fail(static::class .'::'. __FUNCTION__,
|
|
|
+ ['_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => $this->db()->getMessage(), 'body' => []]
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
/**
|
|
|
* 是否相关数据存在
|
|
|
*
|
|
|
* @return bool
|
|
|
*/
|
|
|
- public function exist() {
|
|
|
- if(!$this->properties()) {
|
|
|
+ final public function exist() {
|
|
|
+ $where = $this->getWhereHooker();
|
|
|
+ if(!$where) {
|
|
|
return false;
|
|
|
}
|
|
|
- return (bool) $this->db()->where($this->properties())->selectOne($this->getTable());
|
|
|
+ return (bool) $this->db()->where($where)->selectOne($this->getTable());
|
|
|
}
|
|
|
/**
|
|
|
* 保存数据
|
|
|
*
|
|
|
- * @return mixed|Qii\Driver\Response
|
|
|
+ * @return mixed|Response
|
|
|
* @throws \Exception
|
|
|
*/
|
|
|
- public function add() {
|
|
|
+ final public function add() {
|
|
|
$valid = $this->validFieldsForAdd();
|
|
|
if($valid->isError()) {
|
|
|
return $valid;
|
|
|
}
|
|
|
//如果设置了 unique 就先验证唯一性
|
|
|
- list($uniqueWhere, $uniqueOr, $exclude, $primary) = $this->condition();
|
|
|
+ list($uniqueWhere, $exclude, $primary) = $this->condition();
|
|
|
unset($exclude);
|
|
|
|
|
|
//如果 $where $or 为空,看看主键是否有设置值,有设置值说明验证主键就可以,反之设置了主键,主键值设置了,只验证主键就可以了
|
|
@@ -239,8 +503,8 @@ class Base {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if(count($uniqueWhere) > 0 || count($uniqueOr) > 0) {
|
|
|
- $exist = $this->db()->limit(1)->where($uniqueWhere)->orTerms($uniqueOr)->selectRow($this->getTable());
|
|
|
+ if(count($uniqueWhere) > 0) {
|
|
|
+ $exist = $this->db()->limit(1)->where($uniqueWhere)->selectRow($this->getTable());
|
|
|
if($exist) {
|
|
|
return Response::Exist(static::class .'::'. __FUNCTION__,
|
|
|
['_result' => ['code' => Response::DOES_EXIST, 'msg' => '数据已经存在', 'body' => $exist]]
|
|
@@ -260,50 +524,72 @@ class Base {
|
|
|
['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '添加成功', 'body' => $res]]
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除指定数据
|
|
|
+ *
|
|
|
+ * @return false|Response
|
|
|
+ */
|
|
|
+ public function remove() {
|
|
|
+ if(!$this->properties()) {
|
|
|
+ return Response::FailRemove(static::class .'::'. __FUNCTION__,
|
|
|
+ ['_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => '未指定删除属性,不允许删除', 'body' => 0]
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ $properties = [];
|
|
|
+ foreach ($this->properties() as $key => $val) {
|
|
|
+ $properties[] = $this->entity()->convertToProperty($key);
|
|
|
+ }
|
|
|
+
|
|
|
+ $valid = $this->valid($properties);
|
|
|
+ if($valid->isError()) {
|
|
|
+ return $valid;
|
|
|
+ }
|
|
|
+ $affectedRows = $this->db()->where($this->getWhereHooker())->delete($this->getTable());
|
|
|
+ if($this->db()->isError()) {
|
|
|
+ return Response::FailRemove(static::class .'::'. __FUNCTION__,
|
|
|
+ ['_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => $this->db()->getMessage(), 'body' => 0]
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ return Response::Success(static::class .'::'. __FUNCTION__,
|
|
|
+ ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '删除成功,总共删除了'. $affectedRows . '条记录', 'body' => $affectedRows]]
|
|
|
+ );
|
|
|
+ }
|
|
|
/**
|
|
|
* 更新
|
|
|
*
|
|
|
- * @return mixed | Qii\Driver\Response
|
|
|
+ * @return mixed | Response
|
|
|
* @throws \Exception
|
|
|
*/
|
|
|
- public function update(){
|
|
|
+ final public function update(){
|
|
|
$valid = $this->validFieldsForUpdate();
|
|
|
if($valid->isError()) {
|
|
|
return $valid;
|
|
|
}
|
|
|
- return $this->updateFields();
|
|
|
//检查是否有重复的
|
|
|
- list($uniqueWhere, $uniqueOr, $exclude, $primaryKey) = $this->condition();
|
|
|
+ list($uniqueWhere, $exclude, $primaryKey) = $this->condition();
|
|
|
// 检查 unique 是否已经存在相关数据
|
|
|
$diffWhere = array_diff_assoc($uniqueWhere, $primaryKey);
|
|
|
- $diffOr = array_diff_assoc($uniqueOr, $primaryKey);
|
|
|
- /*print_r(
|
|
|
- [
|
|
|
- 'where' => $uniqueWhere,
|
|
|
- 'or' => $uniqueOr,
|
|
|
- 'exclude' => $exclude,
|
|
|
- 'primary' => $primaryKey
|
|
|
- ]
|
|
|
- );*/
|
|
|
- /*$diffExclude = array_diff_assoc($exclude, $primaryKey);
|
|
|
-
|
|
|
- print_r(
|
|
|
- [
|
|
|
- 'diffWhere' => $diffWhere,
|
|
|
- 'diffOr' => $diffOr,
|
|
|
- 'diffExclude' => $diffExclude
|
|
|
- ]
|
|
|
- );*/
|
|
|
-
|
|
|
- if(count($diffWhere) > 0 || count($diffOr) > 0) {
|
|
|
- $unique = $this->db()->limit(1)->where($diffWhere)->orTerms($diffOr)->exclude($exclude)->selectRow($this->getTable());
|
|
|
+ if(count($diffWhere) > 0) {
|
|
|
+ $unique = $this->db()->limit(1)->where($diffWhere)->exclude($exclude)->selectRow($this->getTable());
|
|
|
if($unique) {
|
|
|
return Response::Exist(static::class .'::'. __FUNCTION__,
|
|
|
['_result' => ['code' => Response::DOES_EXIST, 'msg' => '已经存在相关记录', 'body' => $unique]]
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+ $where = [];
|
|
|
+ $whereHooker = $this->getWhereHooker();
|
|
|
+ foreach ($whereHooker as $key => $val) {
|
|
|
+ $keyArr = explode(':', $key);
|
|
|
+ if(isset($primaryKey[$keyArr[0]])) {
|
|
|
+ unset($primaryKey[$keyArr[0]]);
|
|
|
+ $where[$key] = $val;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(count($where) > 0) {
|
|
|
+ $primaryKey = $where;
|
|
|
+ }
|
|
|
//检查更新的数据是否存在,以主键为主
|
|
|
$exit = $this->db()->limit(1)->where($primaryKey)->selectOne($this->getTable());
|
|
|
if($exit === null || $exit === false) {
|
|
@@ -312,10 +598,10 @@ class Base {
|
|
|
);
|
|
|
}
|
|
|
//获取默认值
|
|
|
+ //更新的时候不使用默认值
|
|
|
+ //$values = array_merge($this->getDefaultValue(), $this->properties());
|
|
|
|
|
|
- $values = array_merge($this->getDefaultValue(), $this->properties());
|
|
|
-
|
|
|
- $affectedRows = $this->db()->updateObject($this->getTable(), $values, $primaryKey);
|
|
|
+ $affectedRows = $this->db()->updateObject($this->getTable(), $this->properties(), $primaryKey);
|
|
|
if($this->db()->isError()) {
|
|
|
return Response::FailUpdate(static::class .'::'. __FUNCTION__,
|
|
|
['_result' => ['code' => Response::FAIL_FOR_UPDATE, 'msg' => $this->db()->getMessage(), 'body' => []]]
|
|
@@ -326,37 +612,25 @@ class Base {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- public function updateFields() {
|
|
|
+ /**
|
|
|
+ * 更新字段
|
|
|
+ *
|
|
|
+ * @return mixed|Response
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ final public function updateFields() {
|
|
|
$properties = $this->properties();
|
|
|
$fields = $this->entity()->convertToProperties(array_keys($properties));
|
|
|
$valid = $this->valid($fields);
|
|
|
if($valid->isError()) {
|
|
|
return $valid;
|
|
|
}
|
|
|
- list($uniqueWhere, $uniqueOr, $exclude, $primaryKey) = $this->condition();
|
|
|
- /*print_r(
|
|
|
- [
|
|
|
- 'where' => $uniqueWhere,
|
|
|
- 'or' => $uniqueOr,
|
|
|
- 'exclude' => $exclude,
|
|
|
- 'primary' => $primaryKey
|
|
|
- ]
|
|
|
- );*/
|
|
|
+ list($uniqueWhere, $exclude, $primaryKey) = $this->condition();
|
|
|
// 检查 unique 是否已经存在相关数据
|
|
|
$diffWhere = array_diff_assoc($uniqueWhere, $primaryKey);
|
|
|
- $diffOr = array_diff_assoc($uniqueOr, $primaryKey);
|
|
|
- /*$diffExclude = array_diff_assoc($exclude, $primaryKey);
|
|
|
-
|
|
|
- print_r(
|
|
|
- [
|
|
|
- 'diffWhere' => $diffWhere,
|
|
|
- 'diffOr' => $diffOr,
|
|
|
- 'diffExclude' => $diffExclude
|
|
|
- ]
|
|
|
- );*/
|
|
|
-
|
|
|
- if(count($diffWhere) > 0 || count($diffOr) > 0) {
|
|
|
- $unique = $this->db()->limit(1)->where($diffWhere)->orTerms($diffOr)->exclude($exclude)->selectRow($this->getTable());
|
|
|
+
|
|
|
+ if(count($diffWhere) > 0) {
|
|
|
+ $unique = $this->db()->limit(1)->where($diffWhere)->exclude($exclude)->selectRow($this->getTable());
|
|
|
if($unique) {
|
|
|
return Response::Exist(static::class .'::'. __FUNCTION__,
|
|
|
['_result' => ['code' => Response::DOES_EXIST, 'msg' => '已经存在相关记录', 'body' => $unique]]
|
|
@@ -364,6 +638,23 @@ class Base {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /*$whereHooker = $this->getWhereHooker();
|
|
|
+ if(!empty($whereHooker)) {
|
|
|
+ $primaryKey = $whereHooker;
|
|
|
+ }*/
|
|
|
+ $where = [];
|
|
|
+ $whereHooker = $this->getWhereHooker();
|
|
|
+ foreach ($whereHooker as $key => $val) {
|
|
|
+ $keyArr = explode(':', $key);
|
|
|
+ if(isset($primaryKey[$keyArr[0]])) {
|
|
|
+ unset($primaryKey[$keyArr[0]]);
|
|
|
+ $where[$key] = $val;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(count($where) > 0) {
|
|
|
+ $primaryKey = $where;
|
|
|
+ }
|
|
|
+
|
|
|
//检查更新的数据是否存在,以主键为主
|
|
|
$exit = $this->db()->limit(1)->where($primaryKey)->selectOne($this->getTable());
|
|
|
if($exit === null || $exit === false) {
|
|
@@ -373,9 +664,10 @@ class Base {
|
|
|
}
|
|
|
//获取默认值
|
|
|
|
|
|
- $values = array_merge($this->getDefaultValue(), $this->properties());
|
|
|
+ //更新的时候不使用默认值
|
|
|
+ //$values = array_merge($this->getDefaultValue(), $this->properties());
|
|
|
|
|
|
- $affectedRows = $this->db()->updateObject($this->getTable(), $values, $primaryKey);
|
|
|
+ $affectedRows = $this->db()->updateObject($this->getTable(), $this->properties(), $primaryKey);
|
|
|
if($this->db()->isError()) {
|
|
|
return Response::FailUpdate(static::class .'::'. __FUNCTION__,
|
|
|
['_result' => ['code' => Response::FAIL_FOR_UPDATE, 'msg' => $this->db()->getMessage(), 'body' => []]]
|
|
@@ -389,12 +681,12 @@ class Base {
|
|
|
/**
|
|
|
* 增加或减少某一个字段的值
|
|
|
*
|
|
|
- * @return mixed|Qii\Driver\Response
|
|
|
+ * @return mixed|Response
|
|
|
* @throws \Exception
|
|
|
*/
|
|
|
- public function incr() {
|
|
|
- list($where, $or, $exclude, $primary) = $this->condition();
|
|
|
- unset($where, $or, $exclude);
|
|
|
+ final public function incr() {
|
|
|
+ list($where, $exclude, $primary) = $this->condition();
|
|
|
+ unset($where, $exclude);
|
|
|
$property = $this->properties();
|
|
|
$incr = [];
|
|
|
foreach ($property as $key => $value) {
|
|
@@ -417,6 +709,17 @@ class Base {
|
|
|
$sets[$key . ':minus'] = $val * -1;
|
|
|
}
|
|
|
}
|
|
|
+ $whereHooker = $this->getWhereHooker();
|
|
|
+ if(!empty($whereHooker)) {
|
|
|
+ foreach ($whereHooker as $key => $where) {
|
|
|
+ //去掉where条件里边的sets的值
|
|
|
+ $keys = $this->explode(":", $key);
|
|
|
+ if(isset($diff[$keys[0]])) {
|
|
|
+ unset($whereHooker[$key]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $primary = $whereHooker;
|
|
|
+ }
|
|
|
$affectedRows = $this->db()->set($sets)->where($primary)->update($this->getTable());
|
|
|
|
|
|
if($this->db()->isError()) {
|
|
@@ -432,11 +735,15 @@ class Base {
|
|
|
/**
|
|
|
* 获取第一条数据
|
|
|
*
|
|
|
- * @return mixed|\Qii\Driver\Response
|
|
|
+ * @return mixed|Response
|
|
|
* @throws \Exception
|
|
|
*/
|
|
|
- public function first() {
|
|
|
+ final public function first() {
|
|
|
$orderBy = $this->getOrderBy();
|
|
|
+ //未设置order by 就以主键为准
|
|
|
+ if(empty($orderBy)) {
|
|
|
+ $orderBy = $this->primaryCondition();
|
|
|
+ }
|
|
|
foreach ($orderBy as $key => $value) {
|
|
|
$orderBy[$key] = 'ASC';
|
|
|
}
|
|
@@ -451,15 +758,19 @@ class Base {
|
|
|
/**
|
|
|
* 获取第一条数据
|
|
|
*
|
|
|
- * @return mixed|\Qii\Driver\Response
|
|
|
+ * @return mixed|Response
|
|
|
* @throws \Exception
|
|
|
*/
|
|
|
- public function last() {
|
|
|
+ final public function last() {
|
|
|
$orderBy = $this->getOrderBy();
|
|
|
+ //未设置order by 就以主键为准
|
|
|
+ if(empty($orderBy)) {
|
|
|
+ $orderBy = $this->primaryCondition();
|
|
|
+ }
|
|
|
foreach ($orderBy as $key => $value) {
|
|
|
$orderBy[$key] = 'DESC';
|
|
|
}
|
|
|
- $row = $this->db()->orderBy($orderBy)->limit(1)->selectRow($this->getTable());
|
|
|
+ $row = $this->db()->fields($this->getFieldsHooker())->orderBy($orderBy)->limit(1)->selectRow($this->getTable());
|
|
|
if($this->db()->isError()) {
|
|
|
return Response::Fail(static::class .'::'. __FUNCTION__, ['_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => 'Query 失败', 'body' => []]]);
|
|
|
}
|
|
@@ -474,24 +785,56 @@ class Base {
|
|
|
* @return array
|
|
|
* @throws \Exception
|
|
|
*/
|
|
|
- public function lists($page = 1, $pageSize = 20) {
|
|
|
+ final public function lists($page = 1, $pageSize = 20) {
|
|
|
$count = $this->count();
|
|
|
if(!$this->initPages($data, $count, $page, $pageSize)) {
|
|
|
return $data;
|
|
|
}
|
|
|
- $order = $this->getOrderBy();
|
|
|
- $data['lists'] = $this->db()->where($this->properties())->orderBy($order)->limit($data['pages']['limitStart'], $pageSize)->selectRows($this->getTable());
|
|
|
-
|
|
|
+ $data['lists'] = $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->limit($data['pages']['limitStart'], $pageSize)->selectRows($this->getTable());
|
|
|
return $data;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取所有数据,这里不分页,但支持限条数,通过 setLimitHooker来实现
|
|
|
+ * $this->setLimitHooker(function(){
|
|
|
+ * return [x,y];//从第x条开始获取y条; return [1];//获取一条 return [0];//获取所有的
|
|
|
+ * });
|
|
|
+ * @return mixed
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ final public function listAll() {
|
|
|
+ return $this->rsCondition()->selectRows($this->getTable());
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 返回指针
|
|
|
+ * @return mixed
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ final public function rs() {
|
|
|
+ return $this->rsCondition()->rs($this->getTable());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通过此方法获取 rs
|
|
|
+ * @return mixed
|
|
|
+ */
|
|
|
+ private function rsCondition() {
|
|
|
+ $limit = $this->getLimitHooker();
|
|
|
+ if(empty($limit) || !is_array($limit)) {
|
|
|
+ return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy());
|
|
|
+ }
|
|
|
+ if(count($limit) == 1) {
|
|
|
+ return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->limit($limit[0]);
|
|
|
+ }
|
|
|
+ return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->limit($limit[0], $limit[1]);
|
|
|
+ }
|
|
|
/**
|
|
|
* 验证相关字段
|
|
|
*
|
|
|
* @param array $fields 字段列表
|
|
|
* @return Response
|
|
|
*/
|
|
|
- public function valid($fields = array()) {
|
|
|
+ final public function valid($fields = array()) {
|
|
|
if(!is_array($fields)) {
|
|
|
return Response::FailValidate(static::class .'::'. __FUNCTION__, ['_result' => ['code' => Response::FAIL_FOR_VALIDATE, 'msg' => '字段必须是数组', 'fields' => []]]);
|
|
|
}
|
|
@@ -505,9 +848,12 @@ class Base {
|
|
|
if(!in_array($key, $fields)) {
|
|
|
continue;
|
|
|
}
|
|
|
+
|
|
|
$field = $this->entity()->convertToField($key);
|
|
|
+ $value = isset($values[$field]) ? $values[$field] : null;
|
|
|
+ $limit = isset($val[2]) ? $val[2]: '';
|
|
|
|
|
|
- $verify = new Verify($val[0], $values[$field] ?? null, strtolower($valid), $val[1], $val[2] ?? '');
|
|
|
+ $verify = new Verify($val[0], $value, strtolower($valid), $val[1], $limit);
|
|
|
$res = $verify->valid();
|
|
|
if($res->isError()) {
|
|
|
$result[] = $res->getResult() .',获取的是 '. $values[$field];
|
|
@@ -526,10 +872,10 @@ class Base {
|
|
|
/**
|
|
|
* 合并多个 valid 结果 $this->>valids($this->valid(['Uid']), $this->valid(['Nickname', 'Email']));
|
|
|
* @param ...
|
|
|
- * @return mixed|Qii\Driver\Response
|
|
|
+ * @return mixed|Response
|
|
|
* @throws \Exception
|
|
|
*/
|
|
|
- public function valids() {
|
|
|
+ final public function valids() {
|
|
|
$validArr = func_get_args();
|
|
|
if(count($validArr) == 0) {
|
|
|
return Response::Success(static::class .'::'. __FUNCTION__, ['_result' => true]);
|
|
@@ -566,28 +912,37 @@ class Base {
|
|
|
*/
|
|
|
protected function uniqueCondition() {
|
|
|
$uniqueWhere = [];
|
|
|
- $uniqueOr = [];
|
|
|
$unique = $this->uniqueKey();
|
|
|
$useWhere = true;
|
|
|
-
|
|
|
+ $condition = [];
|
|
|
+ if(empty($unique)) {
|
|
|
+ return $condition;
|
|
|
+ }
|
|
|
if(!is_array($unique)) {
|
|
|
$unique = $this->explode(',', $unique);
|
|
|
- $useWhere = false;
|
|
|
- if(count($unique) == 1) {
|
|
|
- $useWhere = true;
|
|
|
+ foreach ($unique as $val) {
|
|
|
+ $condition[] = $val;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- foreach ($unique as $key) {
|
|
|
- $key = $this->entity()->convertToField($key);
|
|
|
- $property = $this->entity()->convertToProperty($key);
|
|
|
- if($useWhere) {
|
|
|
- $uniqueWhere[$key] = $this->$property;
|
|
|
+ }else{
|
|
|
+ //检查是否是一维数组,一维数组联合唯一
|
|
|
+ if(count($unique) == count($unique, 1)) {
|
|
|
+ $condition[] = $unique;
|
|
|
}else{
|
|
|
- $uniqueOr[$key] = $this->$property;
|
|
|
+ $condition = $unique;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ foreach ($condition as $item) {
|
|
|
+ $uniqueWhere[] = "OR";
|
|
|
+ $arr = [];
|
|
|
+ foreach ($item as $key) {
|
|
|
+ $key = $this->entity()->convertToField($key);
|
|
|
+ $property = $this->entity()->convertToProperty($key);
|
|
|
+ $arr[$key] = $this->$property;
|
|
|
}
|
|
|
+ $uniqueWhere[] = $arr;
|
|
|
}
|
|
|
- return [$uniqueWhere, $uniqueOr];
|
|
|
+ return $uniqueWhere;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -635,13 +990,13 @@ class Base {
|
|
|
*
|
|
|
* @return array [$uniqueWhere, $uniqueOr, $excludeCondition, $primaryCondition]
|
|
|
*/
|
|
|
- public function condition() {
|
|
|
+ final public function condition() {
|
|
|
//如果设置了 unique 就先验证唯一性,保存的时候验证 uniqueKey,更新的时候验证uniqueKey并排primaryKey
|
|
|
//保存数据的时候验证uniqueKey;更新时验证 uniqueKey,并且排除 primaryKey,如果uniqueKey == primaryKey则不去做唯一性验证
|
|
|
- list($uniqueWhere, $uniqueOr) = $this->uniqueCondition();
|
|
|
+ $uniqueWhere = $this->uniqueCondition();
|
|
|
$excludeCondition = $this->excludeCondition();
|
|
|
$primaryCondition = $this->primaryCondition();
|
|
|
- return [$uniqueWhere, $uniqueOr, $excludeCondition, $primaryCondition];
|
|
|
+ return [$uniqueWhere, $excludeCondition, $primaryCondition];
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -649,9 +1004,12 @@ class Base {
|
|
|
*
|
|
|
* @return array
|
|
|
*/
|
|
|
- public function getOrderBy() {
|
|
|
+ final public function getOrderBy() {
|
|
|
$order = array();
|
|
|
- $orderBy = $this->orderBy();
|
|
|
+ $orderBy = (array) $this->orderBy();
|
|
|
+ if(isset($this->hooker['order']) && is_callable($this->hooker['order']['func'])) {
|
|
|
+ $orderBy = (array) call_user_func($this->hooker['order']['func'], $order, $this->hooker['order']['args']);
|
|
|
+ }
|
|
|
foreach ($orderBy as $key => $val) {
|
|
|
$field = $this->entity()->convertToField($key);
|
|
|
$val = strtoupper($val);
|
|
@@ -660,7 +1018,7 @@ class Base {
|
|
|
}
|
|
|
$order[$field] = $val;
|
|
|
}
|
|
|
- return $order;
|
|
|
+ return (array) $order;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -709,14 +1067,64 @@ class Base {
|
|
|
$data['pages']['pageSize'] = (int) $pageSize;
|
|
|
return true;
|
|
|
}
|
|
|
+ /**
|
|
|
+ * response as object
|
|
|
+ *
|
|
|
+ * @return mixed|\Qii\Driver\Qii\Driver\Response
|
|
|
+ */
|
|
|
+ final public function response() {
|
|
|
+ $properties = $this->properties();
|
|
|
+ if(!$properties) {
|
|
|
+ return Response::Fail(static::class .'::'. __FUNCTION__,
|
|
|
+ ['_result' => ['code' => Response::FAIL_FOR_SELECT, 'msg' => '未找到相关数据', 'body' => []]
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
+ return Response::Success(static::class .'::'. __FUNCTION__,
|
|
|
+ ['_result' => ['code' => Response::DO_SUCCESS, 'msg' => '获取成功', 'body' => $properties]]
|
|
|
+ );
|
|
|
+
|
|
|
+ }
|
|
|
/**
|
|
|
- * 默认转发到 db model上
|
|
|
+ * 方法名 + ByCache/ByRedis/ByMemcache/会将结果缓存,这里使用的缓存类是通过hooker设置的,否则使用对应的
|
|
|
+ * ByClean 则会移除当前缓存, 默认转发到 db model上
|
|
|
* @param string $method method
|
|
|
* @param array $args
|
|
|
* @return mixed
|
|
|
*/
|
|
|
public function __call($method, $args) {
|
|
|
+ $cache = '';
|
|
|
+ preg_match("/(byredis|bymemcache|bycache|byclean)$/i", $method, $matches);
|
|
|
+ if($matches && count($matches) > 0) {
|
|
|
+ $cache = strtolower($matches[0]);
|
|
|
+ }
|
|
|
+ if($cache && in_array($cache, ['bymemcache', 'byredis', 'bycache', 'byclean'])){
|
|
|
+ list($func, $cacheID, $config) = $this->getCacheHooker();
|
|
|
+ $policy = $this->getCacheConfig();
|
|
|
+ if($func == null) {
|
|
|
+ $func = $cache == 'bymemcache' ? $this->db()->setCache('memcached', $policy) : $this->db()->setCache('redis', $policy);
|
|
|
+ }
|
|
|
+ $method = substr($method, 0, strlen($cache) * -1);
|
|
|
+ if (method_exists($this, $method)) {
|
|
|
+ $key = get_called_class() .':'. $method .':'. substr(md5(serialize($this->properties())), -16);
|
|
|
+ if($cache == 'byclean') {
|
|
|
+ return $func->del($key);
|
|
|
+ }
|
|
|
+ if(is_object($func) && method_exists($func, 'get')) {
|
|
|
+ $res = $func->get($key);
|
|
|
+ if ($res) {
|
|
|
+ return unserialize($res);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $expiredAt = isset($config['life_time']) ? (int) $config['life_time'] :
|
|
|
+ (isset($policy['life_time']) ? $policy['life_time'] : $this->defaultExpired);
|
|
|
+ $res = call_user_func_array(array($this, $method), $args);
|
|
|
+ $str = serialize($res);
|
|
|
+ $func->set($key, $str, ['life_time' => $expiredAt]);
|
|
|
+ return $res;
|
|
|
+ }
|
|
|
+ }
|
|
|
return call_user_func_array(array($this->db(), $method), $args);
|
|
|
}
|
|
|
}
|