瀏覽代碼

update entity

朱金辉 1 年之前
父節點
當前提交
d3b48d179c

+ 1 - 1
src/Autoloader/Import.php

@@ -35,7 +35,7 @@ class Import
     /**
      * 包含文件
      * @param string $file 文件路径
-     * @return mix
+     * @return array | mixed
      */
     public static function includes($file)
     {

+ 0 - 1
src/Autoloader/Psr4.php

@@ -325,7 +325,6 @@ class Psr4
             return;
         }
         //去掉第一个斜杠
-        $class = $args[0];
         $class = preg_replace("/^\\\\/", "", $class);
         $class = $this->getClassName($class);
 

+ 1 - 1
src/Base/Controller.php

@@ -126,7 +126,7 @@ abstract class Controller
      */
     final public function enableDB()
     {
-        return $this->db = new Model();
+        return $this->db = _loadClass('\Qii\Driver\Model');
     }
     
     /**

+ 2 - 2
src/Driver/Base.php

@@ -944,7 +944,7 @@ class Base
             {
                 $tmpWhere[$index] = $val;
                 $slices[] = array_values($tmpWhere);
-                unset($tmpWhere);
+                $tmpWhere = array();
             }else {
                 $tmpWhere[$index] = $val;
             }
@@ -963,7 +963,7 @@ class Base
     /**
      * 判断是否是操作符号
      *
-     * @param $val 值
+     * @param mixed $val 值
      * @return bool
      */
     protected function isOperator($val)

+ 328 - 25
src/Driver/Entity/Base.php

@@ -6,15 +6,210 @@ namespace Qii\Driver\Entity;
 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(){
     }
+
+    /**
+     * 默认值,仅在新增数据的时候支持,更新不支持
+     *
+     * @return array
+     */
     public function defaultFieldsValue(){}
+
+    /**
+     * 返回 table 的名字,以便分库分表的时候指定使用
+     *
+     * @return mixed
+     * @throws \Exception
+     */
     public function getTable() {
         throw new \Exception('请先设置需要保存的数据表');
     }
+    /**
+     * set hooker for method
+     * 目前 where 和 order 及 fields 支持
+     * @param $key
+     * @param $hooker
+     * @return void
+     */
+    protected function setHooker($key, $hooker, $args) {
+        $this->hooker[$key]['func'] = $hooker;
+        $this->hooker[$key]['args'] = $args;
+    }
+
+    /**
+     * 设置where hooker
+     * @param object $hooker
+     * @return void
+     * @throws \Exception
+     */
+    public function setWhereHooker($hooker, $args = null) {
+        $this->checkCallable($hooker);
+        $this->setHooker('where', $hooker, $args);
+    }
+    /**
+     * 获取where条件
+     *
+     * @return array|mixed
+     */
+    public function getWhereHooker() {
+        $where = $this->properties();
+        if($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 void
+     * @throws \Exception
+     */
+    public function setOrderHooker($hooker, $args = null) {
+        $this->checkCallable($hooker);
+        $this->setHooker('order', $hooker, $args);
+    }
+
+    /**
+     * 设置 limit hooker
+     *
+     * @param object $hooker
+     * @return void
+     * @throws \Exception
+     */
+    public function setLimitHooker($hooker, $args = null) {
+        $this->checkCallable($hooker);
+        $this->setHooker('order', $hooker, $args);
+    }
+    /**
+     * 获取limit
+     * @return int|mixed
+     */
+    public function getLimitHooker() {
+        if($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 void
+     * @throws \Exception
+     */
+    public function setCacheHooker($hooker, $args = null) {
+        $this->checkCallable($hooker);
+        $this->setHooker('cache', $hooker, $args);
+    }
+
+    /**
+     * 获取Cache Hooker
+     * @return mixed|null[]
+     */
+    public function getCacheHooker() {
+        if($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
+     */
+    public function setCacheConfig($config) {
+        if(!is_array($config)) {
+            return;
+        }
+        self::$config['cache'] = $config;
+    }
+
+    /**
+     * 获取缓存的配置信息
+     *
+     * @return array
+     */
+    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 void
+     * @throws \Exception
+     */
+    public function setQueryFieldsHooker($hooker, $args = null) {
+        if(!is_callable($hooker)) {
+            throw new \Exception('Hooker is un callable');
+        }
+        $this->setHooker('fields', $hooker, $args);
+    }
+
+    /**
+     * 通过field hooker返回查询的字段
+     *
+     * @return mixed|string
+     */
+    public function getFieldsHooker() {
+        if($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 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 mixed
@@ -81,10 +276,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的属性');
     }
@@ -136,7 +351,7 @@ class Base {
      * @throws \Exception
      */
     public function count() {
-        return $this->db()->fields(' COUNT(1) as count')->where($this->properties())->selectOne($this->getTable());
+        return $this->db()->fields(' COUNT(1) as count')->where($this->getWhereHooker())->selectOne($this->getTable());
     }
 
     /**
@@ -148,19 +363,19 @@ class Base {
     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]);
     }
 
@@ -181,17 +396,21 @@ class Base {
         }
         return $this;
     }
-
     /**
      * 获取数据
      *
-     * @return mixed
+     * @return Object
      * @throws \Exception
      */
     public function get() {
-        $info = $this->db()->where($this->properties())->selectRow($this->getTable());
         $class = get_called_class();
         $obj = new $class();
+        $response = $this->info();
+        if($response->isError()) {
+            return $obj;
+        }
+        $info = $response->getResult()['body'];
+
         if(!$info) {
             return $obj;
         }
@@ -201,18 +420,33 @@ class Base {
         }
         return $obj;
     }
-
-
+    /**
+     * 与get不同的这个返回的是Response
+     * @return mixed|\Qii\Driver\Qii\Driver\Response
+     */
+    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()) {
+        $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());
     }
     /**
      * 保存数据
@@ -279,7 +513,7 @@ class Base {
         if($valid->isError()) {
             return $valid;
         }
-        $affectedRows = $this->db()->where($this->properties())->delete($this->getTable());
+        $affectedRows = $this->db()->where($this->getWhereHooker())->delete($this->getTable());
         if($this->db()->isError()) {
             return Response::FailSave(static::class .'::'. __FUNCTION__,
                 ['_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => $this->db()->getMessage(), 'body' => []]
@@ -340,10 +574,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' => []]]
@@ -397,7 +631,6 @@ class Base {
                 );
             }
         }
-
         //检查更新的数据是否存在,以主键为主
         $exit = $this->db()->limit(1)->where($primaryKey)->selectOne($this->getTable());
         if($exit === null || $exit === false) {
@@ -407,9 +640,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' => []]]
@@ -493,7 +727,7 @@ class Base {
         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' => []]]);
         }
@@ -513,13 +747,29 @@ class Base {
         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
+     */
+    public function listAll() {
+        $limit = $this->getLimitHooker();
+        if(empty($limit) || !is_array($limit)) {
+            return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->selectRows($this->getTable());
+        }
+        if(count($limit) == 1) {
+            return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->limit($limit[0])->selectRows($this->getTable());
+        }
+        return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->limit($limit[0], $limit[1])->selectRows($this->getTable());
+    }
+    /**
      * 验证相关字段
      *
      * @param array $fields 字段列表
@@ -686,6 +936,9 @@ class Base {
     public function getOrderBy() {
         $order = array();
         $orderBy = $this->orderBy();
+        if(isset($this->hooker['order']) && is_callable($this->hooker['order']['func'])) {
+            $orderBy = 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);
@@ -743,14 +996,64 @@ class Base {
         $data['pages']['pageSize'] = (int) $pageSize;
         return true;
     }
+    /**
+     * response as object
+     *
+     * @return mixed|\Qii\Driver\Qii\Driver\Response
+     */
+    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' => $config['life_time']]);
+                return $res;
+            }
+        }
         return call_user_func_array(array($this->db(), $method), $args);
     }
 }

+ 18 - 1
src/Driver/Entity/Entity.php

@@ -26,6 +26,9 @@ class Entity {
     public function __construct(){
     }
 
+    public function db() {
+        return _loadClass('\Qii\Driver\Model');
+    }
     /**
      * 设置 entity 的名字空间
      * @param string $namespace 名字空间
@@ -68,7 +71,7 @@ class Entity {
      * @throws \Exception
      */
     public function generateProperties($table, $className = '') {
-        $db = new Model();
+        $db = $this->db();
         $tableInfo = $db->getTableInfo($table);
         if($db->isError()) {
             throw new \Exception($db->getError());
@@ -227,6 +230,11 @@ DOC;
         }, function($tableInfo, $constantJoin){
             return $constantJoin;
         })($tableInfo, $constantJoin);
+
+        $primaryKey = [];
+        if(isset($tableInfo['rules']['extra']) && isset($tableInfo['rules']['extra']['auto_increment'])) {
+            $primaryKey = $tableInfo['rules']['extra']['auto_increment'];
+        }
         $next[] = "\t\treturn ". '$rules;';
         $next[] = "\t". '}';
         $next[] = <<<DOC
@@ -247,7 +255,16 @@ DOC;
      * @throws \Exception
      */
     public function primaryKey(){
+DOC;
+        if($primaryKey) {
+            $next[] = "\t\treturn array('". join("','", $primaryKey). "');";
+        }else{
+            $next[] = <<<DOC
         throw new \Exception('请设置主键');
+DOC;
+        }
+
+        $next[] = <<<DOC
     }
 
     /**

+ 1 - 1
src/Driver/Entity/Verify.php

@@ -60,7 +60,7 @@ class Verify {
                 $verify = $this->Validator->verify(
                     [$this->Key => $this->Value],
                     [$this->Key => [$this->Valid => $this->Limit]],
-                    [$this->Key => ['float' => $this->Message]]
+                    [$this->Key => [$this->Valid => $this->Message]]
                 );
                 break;
         }

+ 0 - 1
src/Driver/Model.php

@@ -27,7 +27,6 @@ use Qii\Config\Register;
  * $fields = array('id' => 1, 'name' => 'test');
  * $test->save($fields);
  */
-
 class Model
 {
     const VERSION = '1.2';

+ 5 - 4
src/Driver/TraitCache.php

@@ -15,8 +15,8 @@ trait TraitCache
      */
     final public function setCache($cache, $policy)
     {
-        Import::requires(QII_DIR . DS . 'Qii' . DS . 'Cache.php');
-        $this->cache = Psr4::loadClass('\Qii\Cache', $cache)->initialization($policy);//载入cache类文件
+        $this->cache = \Qii::getInstance()->setCache($cache, $policy);
+        return $this->cache;
     }
 
     /**
@@ -24,11 +24,12 @@ trait TraitCache
      *
      * @param String $id
      * @param Array $value
+     * @param array $policy ['life_time' => 过期时间]
      * @return Bool
      */
-    final public function cache($id, $value)
+    final public function cache($id, $value, $policy = array())
     {
-        return $this->cache->set($id, $value);
+        return $this->cache->set($id, $value, $policy);
     }
 
     /**

+ 2 - 1
src/Functions/Funcs.php

@@ -2,6 +2,7 @@
 
 use Qii\Autoloader\Import;
 use Qii\Autoloader\Psr4;
+use Qii\Language\Loader;
 
 /**
  * Qii ...
@@ -42,7 +43,7 @@ function _log() {
  */
 function _language($language, $dir = '')
 {
-	\Qii\Language\Loader::getInstance()->load($language, $dir);
+	Loader::getInstance()->load($language, $dir);
 }
 
 /**