Jelajahi Sumber

Update: fixed some error

朱金辉 1 tahun lalu
induk
melakukan
95761b79d2

+ 2 - 1
src/Autoloader/Import.php

@@ -45,7 +45,8 @@ class Import
             }, $file);
         }
         $file = str_replace(array('\\', '/'), DS, $file);
-        if (self::getIncludeFiles($file) !== null) self::getIncludeFiles($file);
+        $config = self::getIncludeFiles($file);
+        if ($config !== null) $config;
         if(!file_exists($file)) {
             throw new FileNotFound($file, 404);
         }

+ 10 - 0
src/Base/Request.php

@@ -172,6 +172,16 @@ abstract class Request
     }
 
     /**
+     * isPut
+     *
+     * @param void
+     * @return boolean
+     */
+    public function isDelete()
+    {
+        return (strtoupper($this->method) == 'DELETE');
+    }
+    /**
      * isHead
      *
      * @param void

+ 22 - 4
src/Driver/Base.php

@@ -355,7 +355,7 @@ class Base
         if(count($set) == 0) {
             return $this;
         }
-        $operator = array("equal" => "%s`%s` = '%s'", "plus" => "%s`%s` = %s`%s`+%s", "minus" => "%s`%s` = %s`%s`-%s", "multiply" => "%s`%s` = %s`%s`*%s", "divide" => "%s`%s` = %s`%s`/%s");
+        $operator = array("equal" => "%s`%s` = '%s'", "unequal" => "%s`%s` != '%s'", "plus" => "%s`%s` = %s`%s`+%s", "minus" => "%s`%s` = %s`%s`-%s", "multiply" => "%s`%s` = %s`%s`*%s", "divide" => "%s`%s` = %s`%s`/%s");
         foreach($set as $key => $val)
         {
             $val = $this->setQuote($val);
@@ -666,6 +666,9 @@ class Base
         if (ini_get("magic_quotes_gpc")) {
             return $word;
         }
+        if(in_array(gettype($val), array("object", "resource","resource (closed)"))) {
+            throw new \Exception('期待参数为数组或字符串,获取到的是:'. gettype($word)."(". json_encode($word) .")");
+        }
         return is_array($word) ? array_map('addslashes', $word) : addslashes($word);
     }
     /**
@@ -833,7 +836,7 @@ class Base
      */
     protected function getFieldAlias($name, $connector = ".")
     {
-        $aliases = explode('.', $name);
+        $aliases = explode('.', $name, 2);
         if(count($aliases) == 1) {
             return array('alias' => '', 'name' => $name);
         }
@@ -932,6 +935,11 @@ class Base
         $lastIsValue = null;
         foreach($group as $index => $val)
         {
+            //in比较特殊,它可以是字符串,可以是数组,结果是数组就单独处理不走操作符的处理逻辑
+            if(substr($index, -3)  == ':in' && is_array($val)) {
+                $tmpWhere[$index] = $val;
+                continue;
+            }
             $isOperator = $this->isOperator($val);//如果是操作符,上一个不是操作符就清空tmpWhere,并放入slices
             $isValue = !$isOperator;
             if($lastIsValue && $isOperator)
@@ -972,6 +980,9 @@ class Base
             return false;
         }
         if(!is_array($val)) {
+            if(in_array(gettype($val), array("array", "object", "resource","resource (closed)"))) {
+                throw new \Exception("期待参数为字符串,获取到的为: " . gettype($val) ."(". json_encode($val) . ")");
+            }
             $val = strtolower($val);
         }
         return in_array($val, $this->operateVal) || in_array($val, $this->operateTable);
@@ -1042,10 +1053,17 @@ class Base
             $operate = $this->getFieldOperator($aliases['name']);
             $opt = $operate['operator'] ? $operate['operator'] : $defaultOperate;
             $name =  $operate['field'];
-            if($opt == 'in' && is_array($val))
+            if($opt == 'in')
             {
-                $where[] = sprintf($operator[$opt], $alias, $name, "'". join("','", $val) . "'");
+                if(is_array($val)) {
+                    $where[] = sprintf($operator[$opt], $alias, $name, "'". join("','", $val) . "'");
+                }else{
+                    $where[] = sprintf($operator[$opt], $alias, $name, $val);
+                }
             }else{
+                if(!isset($operator[$opt])) {
+                    throw new \Exception("Unknow operator " . $opt, __LINE__);
+                }
                 $where[] = sprintf($operator[$opt], $alias, $name, $this->setQuote($val));
             }
             $lastIsValue = $isValue;

+ 159 - 120
src/Driver/Entity/Base.php

@@ -1,9 +1,7 @@
 <?php
 namespace Qii\Driver\Entity;
 
-
-
-use Qii\Driver\Response;
+use \Qii\Driver\Response;
 
 class Base {
     /**
@@ -54,6 +52,7 @@ class Base {
     protected function setHooker($key, $hooker, $args) {
         $this->hooker[$key]['func'] = $hooker;
         $this->hooker[$key]['args'] = $args;
+        return $this;
     }
 
     /**
@@ -62,9 +61,10 @@ class Base {
      * @return void
      * @throws \Exception
      */
-    public function setWhereHooker($hooker, $args = null) {
+    final public function setWhereHooker($hooker, $args = null) {
         $this->checkCallable($hooker);
         $this->setHooker('where', $hooker, $args);
+        return $this;
     }
     /**
      * 获取where条件
@@ -85,9 +85,10 @@ class Base {
      * @return void
      * @throws \Exception
      */
-    public function setOrderHooker($hooker, $args = null) {
+    final public function setOrderHooker($hooker, $args = null) {
         $this->checkCallable($hooker);
         $this->setHooker('order', $hooker, $args);
+        return $this;
     }
 
     /**
@@ -97,15 +98,16 @@ class Base {
      * @return void
      * @throws \Exception
      */
-    public function setLimitHooker($hooker, $args = null) {
+    final public function setLimitHooker($hooker, $args = null) {
         $this->checkCallable($hooker);
-        $this->setHooker('order', $hooker, $args);
+        $this->setHooker('limit', $hooker, $args);
+        return $this;
     }
     /**
      * 获取limit
      * @return int|mixed
      */
-    public function getLimitHooker() {
+    final 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']);
         }
@@ -120,16 +122,17 @@ class Base {
      * @return void
      * @throws \Exception
      */
-    public function setCacheHooker($hooker, $args = null) {
+    final public function setCacheHooker($hooker, $args = null) {
         $this->checkCallable($hooker);
         $this->setHooker('cache', $hooker, $args);
+        return $this;
     }
 
     /**
      * 获取Cache Hooker
      * @return mixed|null[]
      */
-    public function getCacheHooker() {
+    final 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']);
         }
@@ -142,7 +145,7 @@ class Base {
      * @param array $config 缓存配置
      * @return void
      */
-    public function setCacheConfig($config) {
+    final public function setCacheConfig($config) {
         if(!is_array($config)) {
             return;
         }
@@ -154,7 +157,7 @@ class Base {
      *
      * @return array
      */
-    public function getCacheConfig() {
+    final public function getCacheConfig() {
         if(is_array(self::$config) && isset(self::$config['cache']) && is_array(self::$config['cache'])) {
             return self::$config['cache'];
         }
@@ -178,11 +181,12 @@ class Base {
      * @return void
      * @throws \Exception
      */
-    public function setQueryFieldsHooker($hooker, $args = null) {
+    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;
     }
 
     /**
@@ -190,7 +194,7 @@ class Base {
      *
      * @return mixed|string
      */
-    public function getFieldsHooker() {
+    final 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']);
         }
@@ -202,7 +206,7 @@ class Base {
      * @param string $field
      * @return mixed
      */
-    public function getFieldVal($field) {
+    final public function getFieldVal($field) {
         if(!preg_match('/^[a-zA-Z]/', $field)) {
             throw new \Exception('Field is illegal');
         }
@@ -214,7 +218,7 @@ class Base {
      *
      * @return mixed
      */
-    public function db() {
+    final public function db() {
         return _loadClass('\Qii\Driver\Model');
     }
 
@@ -222,7 +226,7 @@ class Base {
      * 返回 entity 信息
      * @return mixed
      */
-    public function entity() {
+    final public function entity() {
         return _loadClass('\Qii\Driver\Entity\Entity');
     }
 
@@ -308,7 +312,7 @@ class Base {
      *
      * @return array
      */
-    public function properties() {
+    final public function properties() {
         $class = get_called_class();
         $method = new \ReflectionClass($class);
         $properties = $method->getproperties();
@@ -331,7 +335,7 @@ class Base {
      *
      * @return array
      */
-    public function getDefaultValue() {
+    final public function getDefaultValue() {
         $default = [];
         $defaultValue = $this->defaultFieldsValue();
         if(!$defaultValue || !is_array($defaultValue) || count($defaultValue) == 0) {
@@ -350,7 +354,7 @@ class Base {
      * @return mixed
      * @throws \Exception
      */
-    public function count() {
+    final public function count() {
         return $this->db()->fields(' COUNT(1) as count')->where($this->getWhereHooker())->selectOne($this->getTable());
     }
 
@@ -360,7 +364,7 @@ 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::$properties[$class])) {
@@ -384,7 +388,7 @@ class Base {
      * @param $values
      * @return $this|false
      */
-    public function bindValues($values) {
+    final public function bindValues($values) {
         if(!is_array($values)) {
             return $this;
         }
@@ -402,7 +406,7 @@ class Base {
      * @return Object
      * @throws \Exception
      */
-    public function get() {
+    final public function get() {
         $class = get_called_class();
         $obj = new $class();
         $response = $this->info();
@@ -424,7 +428,7 @@ class Base {
      * 与get不同的这个返回的是Response
      * @return mixed|\Qii\Driver\Qii\Driver\Response
      */
-    public function info() {
+    final public function info() {
         try{
             $info = $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->selectRow($this->getTable());
             return Response::Success(static::class .'::'. __FUNCTION__,
@@ -441,7 +445,7 @@ class Base {
      *
      * @return bool
      */
-    public function exist() {
+    final public function exist() {
         $where = $this->getWhereHooker();
         if(!$where) {
             return false;
@@ -451,16 +455,16 @@ class Base {
     /**
      * 保存数据
      *
-     * @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 为空,看看主键是否有设置值,有设置值说明验证主键就可以,反之设置了主键,主键值设置了,只验证主键就可以了
@@ -473,8 +477,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]]
@@ -502,7 +506,9 @@ class Base {
      */
     public function remove() {
         if(!$this->properties()) {
-            return false;
+            return Response::FailRemove(static::class .'::'. __FUNCTION__,
+                ['_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => '未指定删除属性,不允许删除', 'body' => 0]
+                ]);
         }
         $properties = [];
         foreach ($this->properties() as $key => $val) {
@@ -515,8 +521,8 @@ class Base {
         }
         $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' => []]
+            return Response::FailRemove(static::class .'::'. __FUNCTION__,
+                ['_result' => ['code' => Response::FAIL_FOR_SAVE, 'msg' => $this->db()->getMessage(), 'body' => 0]
                 ]);
         }
         return Response::Success(static::class .'::'. __FUNCTION__,
@@ -526,46 +532,42 @@ class Base {
     /**
      * 更新
      *
-     * @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;
         }
         //检查是否有重复的
-        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]]
                 );
             }
         }
-
+        /*$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) {
@@ -591,46 +593,46 @@ class Base {
     /**
      * 更新字段
      *
-     * @return mixed|\Qii\Driver\Qii\Driver\Response|Response
+     * @return mixed|Response
      * @throws \Exception
      */
-    public function updateFields() {
+    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]]
                 );
             }
         }
+
+        /*$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) {
@@ -657,12 +659,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) {
@@ -685,6 +687,10 @@ class Base {
                 $sets[$key . ':minus'] = $val * -1;
             }
         }
+        $whereHooker = $this->getWhereHooker();
+        if(!empty($whereHooker)) {
+            $primary = $whereHooker;
+        }
         $affectedRows = $this->db()->set($sets)->where($primary)->update($this->getTable());
 
         if($this->db()->isError()) {
@@ -700,11 +706,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';
         }
@@ -719,11 +729,15 @@ 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';
         }
@@ -742,7 +756,7 @@ 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;
@@ -759,15 +773,31 @@ class Base {
      * @return mixed
      * @throws \Exception
      */
-    public function listAll() {
+    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())->selectRows($this->getTable());
+            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])->selectRows($this->getTable());
+            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])->selectRows($this->getTable());
+        return $this->db()->fields($this->getFieldsHooker())->where($this->getWhereHooker())->orderBy($this->getOrderBy())->limit($limit[0], $limit[1]);
     }
     /**
      * 验证相关字段
@@ -775,7 +805,7 @@ class Base {
      * @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' => []]]);
         }
@@ -810,10 +840,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]);
@@ -850,28 +880,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;
     }
 
     /**
@@ -919,13 +958,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];
     }
 
     /**
@@ -933,11 +972,11 @@ 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 = call_user_func($this->hooker['order']['func'], $order, $this->hooker['order']['args']);
+            $orderBy = (array) call_user_func($this->hooker['order']['func'], $order, $this->hooker['order']['args']);
         }
         foreach ($orderBy as $key => $val) {
             $field = $this->entity()->convertToField($key);
@@ -947,7 +986,7 @@ class Base {
             }
             $order[$field] = $val;
         }
-        return $order;
+        return (array) $order;
     }
 
     /**
@@ -1001,7 +1040,7 @@ class Base {
      *
      * @return mixed|\Qii\Driver\Qii\Driver\Response
      */
-    public function response() {
+    final public function response() {
         $properties = $this->properties();
         if(!$properties) {
             return Response::Fail(static::class .'::'. __FUNCTION__,
@@ -1050,7 +1089,7 @@ class Base {
                     (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']]);
+                $func->set($key, $str, ['life_time' => $expiredAt]);
                 return $res;
             }
         }

+ 116 - 13
src/Driver/Entity/Entity.php

@@ -2,6 +2,7 @@
 namespace Qii\Driver\Entity;
 
 use Qii\Driver\Model;
+use Qii\Driver\Response;
 
 /**
  * 通过数据表生成 entity
@@ -108,6 +109,10 @@ class Entity {
                 $doc[] = "\t/**";
                 $doc[] = "\t * @var float ". $convertField . $comment;
                 $doc[] = "\t */";
+            }else if($tableInfo['rules']['decimal'] && isset($tableInfo['rules']['decimal'][$field])) {
+                $doc[] = "\t/**";
+                $doc[] = "\t * @var decimal ". $convertField . $comment;
+                $doc[] = "\t */";
             }
             if($tableInfo['rules']['default'] && isset($tableInfo['rules']['default'][$field])) {
                 $default = $tableInfo['rules']['default'][$field];
@@ -127,6 +132,31 @@ class Entity {
         $classAndProperty[] = "use Qii\Driver\Entity\Inf;";
         $classAndProperty[] = "use Qii\Driver\Entity\Base;";
         $classAndProperty[] = "\n";
+        $classAndProperty[] = <<<DOC
+/**
+ * @method \$this setWhereHooker(callable \$func)
+ * @method \$this setOrderHooker(callable \$func)
+ * @method \$this setLimitHooker(callable \$func)
+ * @method \$this setCacheHooker(callable \$func)
+ * @method \$this setQueryFieldsHooker(callable \$func)
+ * @method bool exit()
+ * @method \$this get()
+ * @method Response info()
+ * @method Response save()
+ * @method Response remove()
+ * @method Response update()
+ * @method Response updateFields()
+ * @method Response incr()
+ * @method Response first()
+ * @method Response last()
+ * @method array lists(int \$page, int \$pageSize)
+ * @method array listAll()
+ * @method Object rs()
+ * @method Response valids
+ * @method array initPages(array \$data, int \$count, int \$page, int \$pageSize)
+ */
+DOC;
+
         $classAndProperty[] = 'class '. $class . ' extends Base implements Inf{';
         $dynamicProperty = [];
         foreach ($properties as $property) {
@@ -153,7 +183,6 @@ class Entity {
      * 动态变化的日期,初始化的时候赋值
      */
 DOC;
-            ;
             $classAndProperty[] = "\tpublic function __construct(){";
             $classAndProperty[] = "\n";
             $classAndProperty[] = "\t}";
@@ -183,6 +212,7 @@ DOC;
 \t}
 DOC;
 
+
         //生成 table rules
         $classAndProperty[] = $this->generateRules($tableInfo);
         $classAndProperty[] = '}';
@@ -198,7 +228,7 @@ DOC;
     public function rules() { 
 DOC;
         $constantJoin[] = "\t\t". '$rules = [];';
-        $next = array_reduce(array_reverse(['required', 'int', 'minlength', 'maxlength', 'timestamp', 'datetime']), function($carry, $item){
+        $next = array_reduce(array_reverse(['required', 'int', 'minlength', 'maxlength', 'decimal', 'timestamp', 'datetime']), function($carry, $item){
             return function() use ($carry, $item){
                 $tableInfo = func_get_args()[0];
                 $constantJoin = func_get_args()[1];
@@ -212,6 +242,9 @@ DOC;
                     case 'int':
                         $join = $this->generateInt($currentRules, $comments);
                         break;
+                    case 'decimal':
+                        $join = $this->generateDecimal($currentRules, $comments);
+                        break;
                     case 'minlength':
                         $join = $this->generateMinLength($currentRules, $comments);
                         break;
@@ -231,21 +264,55 @@ DOC;
             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". '}';
+        //主键自动添加
+        $primaryKey = array();
+        if(isset($tableInfo['rules']['pri'])) {
+            $primaryKey = $tableInfo['rules']['pri'];
+        }
+        //保存验证的时候使用 required 并去掉pri和default里边的内容
+        $defaults = array();
+        if(isset($tableInfo['rules']['default'])) {
+            $defaults = array_keys($tableInfo['rules']['default']);
+        }
+        $validForSave = array();
+        if(isset($tableInfo['rules']) && isset($tableInfo['rules']['required'])) {
+            foreach ($tableInfo['rules']['required'] as $field) {
+                if(!in_array($field, $primaryKey) && !in_array($field, $defaults)) {
+                    $validForSave[] = $this->convertToProperty($field);
+                }
+            }
+        }
+        $uniKey = array();
+        if(isset($tableInfo['rules']) && isset($tableInfo['rules']['uniq'])) {
+            foreach ($tableInfo['rules']['uniq'] as $uniq) {
+                $uniKey[] = $this->convertToProperties($uniq);
+            }
+        }
+
         $next[] = <<<DOC
     /**
      * unique (unique 如果是 array 则表示 联合唯一,如果是string则是任意唯一,多个单独唯一使用字符串以逗号隔开, 主键除外)
-     *
+     * array(array1, array2) , array1 和array 2单独唯一
      * @return mixed
      * @throws \Exception
      */
     public function uniqueKey(){
-        throw new \Exception('请设置唯一值');
+DOC;
+        if(count($uniKey) > 0) {
+            $uniq = array();
+            foreach ($uniKey as $val) {
+                $uniq[] = "array('". join("','", $val). "')";
+            }
+            $next[] = "\t\treturn array(". join(", ", $uniq). ");";
+        }else{
+            $next[] = <<<DOC
+        return array();
+DOC;
+        }
+
+        $next[] = <<<DOC
     }
 
     /**
@@ -257,7 +324,7 @@ DOC;
     public function primaryKey(){
 DOC;
         if($primaryKey) {
-            $next[] = "\t\treturn array('". join("','", $primaryKey). "');";
+            $next[] = "\t\treturn array('". join("','", $this->convertToProperties($primaryKey)). "');";
         }else{
             $next[] = <<<DOC
         throw new \Exception('请设置主键');
@@ -279,19 +346,24 @@ DOC;
      * 添加时验证的字段,自行添加
      */
     public function validFieldsForAdd(){
-        \$fields = [];
+    DOC;
+        if(count($validForSave) > 0) {
+            $next[] = "\t\$fields = array('". join("', '", $validForSave)."');";
+        }else{
+            $next[] = "\t\$fields = array();";
+        }
+        $next[] = <<<DOC
         return \$this->valid(\$fields);
     }
     
     /**
-     * 验证更新时的字段,自行添加
+     * 更新时验证的字段,自行添加
      */
     public function validFieldsForUpdate() {
-        \$fields = [];
+        \$fields = array();
         return \$this->valid(\$fields);
     }
 DOC;
-
         return join("\n", $next);
     }
 
@@ -395,6 +467,13 @@ DOC;
         $constantJoin[] = "\t\t];";
         return $constantJoin;
     }
+
+    /**
+     * int 类型数据
+     * @param $rules
+     * @param $comments
+     * @return array
+     */
     public function generateInt($rules, $comments = array()) {
         $constantJoin = [];
 
@@ -435,6 +514,30 @@ DOC;
 
         return array_merge($constantJoin, $intProperty['min'], $intProperty['max'], $intProperty['number']);
     }
+    public function generateDecimal($rules, $comments = array()) {
+        $constantJoin = [];
+
+        if(!$rules || !is_array($rules)) {
+            return $constantJoin;
+        }
+        $constantJoin = [];
+        $constantJoin[] = "\t\t". '$rules["decimal"] = [';
+        $joinProperty = [];
+        foreach ($rules as $key => $val) {
+            $comment = '';
+            if(isset($comments[$key]) && $comments[$key] != "") {
+                $comment = $comments[$key];
+            }
+
+            $message = ($comment != '' ? $comment : $key) . "格式示例: ". str_repeat(6, min(1, (int)$val[0] - (int)$val[1])) . ".". str_repeat(6, (int)$val[1]);
+            $joinProperty[] = <<<DOC
+    \t\t["{$this->convertToProperty($key)}", "{$message}", "{$val[0]},{$val[1]}"]
+DOC;
+        }
+        $constantJoin[] = join(",\n", $joinProperty);
+        $constantJoin[] = "\t\t];";
+        return $constantJoin;
+    }
     /**
      * 转换为属性,属性会将下划线+小写/大写 转换成大写
      *

+ 31 - 5
src/Driver/TraitDatabase.php

@@ -71,8 +71,12 @@ trait TraitDatabase
      */
     public function getTableInfo($table, $database = null, $autoIncr = null)
     {
+        static $tableInfo;
+        if(isset($tableInfo[$table])) {
+            return $tableInfo[$table];
+        }
         if (!$database) $database = $this->currentDB;
-        $sql = "SELECT * from information_schema.COLUMNS where table_name = '" . $table . "' and table_schema = '" . $database . "'";
+        $sql = "SELECT * from information_schema.COLUMNS where table_name = '" . $table . "' and table_schema = '" . $database . "' ORDER BY ORDINAL_POSITION ASC";
         $data = array(
             'table' => $table,
             'fields' => array(),
@@ -81,7 +85,6 @@ trait TraitDatabase
                 'required' => array()
             )
         );
-
         $rs = $this->setQuery($sql);
         $maxRange = [
             'bigint' => [-1 * pow(2, 63), pow(2, 63)-1],
@@ -91,21 +94,26 @@ trait TraitDatabase
             'tinyint' => [-128, 127],
             'integer' => [-1 * pow(2, 31), pow(2, 31)-1]
         ];
+        $data['type'] = [];
         while ($row = $rs->fetch()) {
             $data['fields'][] = $row['COLUMN_NAME'];
+            $data['type'][$row['DATA_TYPE']][] = $row['COLUMN_NAME'];
             if ($row['EXTRA']) {
                 $data['rules']['extra'][$row['EXTRA']][] = $row['COLUMN_NAME'];
             }
             if ($row['COLUMN_KEY'] == 'PRI') {
                 $data['rules']['pri'][] = $row['COLUMN_NAME'];
                 $data['rules']['required'][] = $row['COLUMN_NAME'];
+            } else if($row['COLUMN_KEY'] == 'UNI'){
+                //$data['rules']['uni'][] = $row['COLUMN_NAME'];
+                $data['rules']['required'][] = $row['COLUMN_NAME'];
             }else if ($row['IS_NULLABLE'] == 'NO') {
                 $data['rules']['required'][] = $row['COLUMN_NAME'];
             }
             if (in_array($row['DATA_TYPE'], array('varchar', 'char'))) {
                 $data['rules']['maxlength'][$row['COLUMN_NAME']] = $row['CHARACTER_MAXIMUM_LENGTH'];
             }
-            if (in_array($row['DATA_TYPE'], array('mediumtext', 'TINYTEXT', 'text', 'longtext'))) {
+            if (in_array($row['DATA_TYPE'], array('mediumtext', 'tinytext', 'text', 'longtext'))) {
                 $data['rules']['text'][] = $row['COLUMN_NAME'];
             }
             if (in_array($row['DATA_TYPE'], array('bigint', 'int', 'mediumint', 'smallint', 'tinyint', 'integer'))) {
@@ -115,10 +123,13 @@ trait TraitDatabase
                     $data['rules']['number'][] = $row['COLUMN_NAME'];
                 }
             }
-            if (in_array($row['DATA_TYPE'], array('float', 'double', 'decimal'))) {
+            if (in_array($row['DATA_TYPE'], array('float', 'double'))) {
                 $data['rules']['float'][$row['COLUMN_NAME']] = $this->getValueFromBrackets($row['COLUMN_TYPE']);
             }
-            if (in_array($row['DATA_TYPE'], array('timestamp', 'datatime'))) {
+            if (in_array($row['DATA_TYPE'], array('decimal'))) {
+                $data['rules']['decimal'][$row['COLUMN_NAME']] = $this->getValueFromBrackets($row['COLUMN_TYPE']);
+            }
+            if (in_array($row['DATA_TYPE'], array('timestamp', 'datetime'))) {
                 $data['rules']['timestamp'][] = $row['COLUMN_NAME'];
             }
             if (in_array($row['DATA_TYPE'], array('enum', 'set'))) {
@@ -131,7 +142,22 @@ trait TraitDatabase
                 $data['comment'][$row['COLUMN_NAME']] = $row['COLUMN_COMMENT'];
             }
         }
+
+        $sql = "SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE table_name = '" . $table . "'";
+        $rs = $this->setQuery($sql);
         $data['sql'] = $this->getTableSQL($table, $database, $autoIncr);
+        preg_match_all("/UNIQUE\sKEY\s`(.*?)`\s\(`(.*?)`\)/", $data['sql'], $matches);
+        $uniqKeys = [];
+        if(count($matches) == 3) {
+            foreach ($matches[2] as $key => $match) {
+                //$uniqKeys[$matches[1][$key]] = explode("`,`", $match);
+                $uniqKeys[] = explode("`,`", $match);
+            }
+        }
+        if(count($uniqKeys) > 0) {
+            $data['rules']['uniq'] = $uniqKeys;
+        }
+        $tableInfo[$table] = $data;
         return $data;
     }
 

+ 3 - 2
src/Library/Validate.php

@@ -530,8 +530,9 @@ class Validate
     public function decimal($str, $decimal)
     {
         $decimalArr = explode(',', $decimal);
-
-        return preg_match("/^(([1-9]\d*)|0{1,". $decimalArr[0] ."})(\.\d{".$decimalArr[1]."})?$/", $str);
+        $left = $decimalArr[0] - $decimalArr[1];
+        $right = $decimalArr[1];
+        return preg_match("/^\d{1,".$left."}\.\d{".$right."}$/", $str);;
     }
 
     /**

+ 0 - 220
src/Request/Simple.php

@@ -1,220 +0,0 @@
-<?php
-namespace Qii\Request;
-
-use Qii\Base\Request;
-
-final class Simple extends Request
-{
-	/**
-	 * __construct
-	 *
-	 * @param string $module
-	 * @param string $controller
-	 * @param string $action
-	 * @param string $method
-	 * @param array $params
-	 */
-	public function __construct ($module, $controller, $action, $method, $params = null)
-	{
-		if ($params && !is_array($params)) {
-			trigger_error('Expects the params is an array', E_USER_ERROR);
-			return false;
-		}
-
-		if (is_string($method)) {
-			$this->method = $method;
-		} else {
-			if (isset($_SERVER['REQUEST_METHOD'])) {
-				$this->method = $_SERVER['REQUEST_METHOD'];
-			} else {
-				if (!strncasecmp(PHP_SAPI, 'cli', 3)) {
-					$this->method = 'CLI';
-				} else {
-					$this->method = 'Unknown';
-				}
-			}
-		}
-
-		if ($module || $controller || $action) {
-			if ($module && is_string($module)) {
-				$this->module = $module;
-			} else {
-				$this->module = YAF_G('default_module');
-			}
-
-			if ($controller && is_string($controller)) {
-				$this->controller = $controller;
-			} else {
-				$this->controller = YAF_G('default_controller');
-			}
-
-			if ($action && is_string($action)) {
-				$this->action = $action;
-			} else {
-				$this->controller = YAF_G('default_action');
-			}
-
-			$this->routed = true;
-		} else {
-			$argv = $this->getServer('argv');
-			if (is_array($argv)) {
-				foreach($argv as $value) {
-					if (is_string($value)) {
-						if (strncasecmp($value, 'request_uri=', 12)) {
-							continue;
-						}
-						$query = substr($value, 12);
-						break;
-					}
-				}
-			}
-
-			if (empty($query)) {
-				$this->uri = '';
-			} else {
-				$this->uri = $query;
-			}
-		}
-
-		if ($params && is_array($params)) {
-			$this->params = $params;
-		} else {
-			$this->params = array();
-		}
-        parent::__construct();
-	}
-	
-	/**
-	 * getQuery
-	 *
-	 * @param string $name
-	 * @param mixed $default
-	 * @return mixed
-	 */
-	public function getQuery($name = null, $default = null)
-	{
-		if (is_null($name)) {
-			return $_GET;
-		} elseif (isset($_GET[$name])) {
-			return $_GET[$name];
-		}
-		return $default;
-	}
-
-	/**
-	 * getRequest
-	 *
-	 * @param string $name
-	 * @param mixed $default
-	 * @return mixed
-	 */
-	public function getRequest($name = null, $default = null)
-	{
-		if (is_null($name)) {
-			return $_REQUEST;
-		} elseif (isset($_REQUEST[$name])) {
-			return $_REQUEST[$name];
-		}
-		return $default;
-	}
-
-	/**
-	 * getPost
-	 *
-	 * @param string $name
-	 * @param mixed $default
-	 * @return mixed
-	 */
-	public function getPost($name = null, $default = null)
-	{
-		if (is_null($name)) {
-			return $_POST;
-		} elseif (isset($_POST[$name])) {
-			return $_POST[$name];
-		}
-		return $default;
-	}
-
-	/**
-	 * getCookie
-	 *
-	 * @param string $name
-	 * @param mixed $default
-	 * @return mixed
-	 */
-	public function getCookie($name = null, $default = null)
-	{
-		if (is_null($name)) {
-			return $_COOKIE;
-		} elseif (isset($_COOKIE[$name])) {
-			return $_COOKIE[$name];
-		}
-		return $default;
-	}
-
-	/**
-	 * getFiles
-	 *
-	 * @param string $name
-	 * @param mixed $default
-	 * @return mixed
-	 */
-	public function getFiles($name = null, $default = null)
-	{
-		if (is_null($name)) {
-			return $_FILES;
-		} elseif (isset($_FILES[$name])) {
-			return $_FILES[$name];
-		}
-		return $default;
-	}
-
-	/**
-	 * get [params -> post -> get -> cookie -> server]
-	 *
-	 * @param string $name
-	 * @param mixed $default
-	 * @return mixed
-	 */	
-	public function get($name, $default = null)
-	{
-		if (isset($this->params[$name])) {
-			return $this->params[$name];
-		} elseif (isset($_POST[$name])) {
-			return $_POST[$name];
-		} elseif (isset($_GET[$name])) {
-			return $_GET[$name];
-		} elseif (isset($_COOKIE[$name])) {
-			return $_COOKIE[$name];
-		} elseif (isset($_SERVER[$name])) {
-			return $_SERVER[$name];
-		}
-		return $default;
-	}
-
-	/**
-	 * isXmlHttpRequest
-	 *
-	 * @param void
-	 * @return boolean
-	 */	
-	public function isXmlHttpRequest()
-	{
-		$header = isset($_SERVER['HTTP_X_REQUESTED_WITH']) ? $_SERVER['X-Requested-With'] : '';
-		if (is_string($header) && strncasecmp('XMLHttpRequest', $header, 14) == 0) {
-			return true;
-		}
-		return false;
-	}
-
-	/**
-	 * __clone
-	 *
-	 * @param void
-	 */
-	private function __clone()
-	{
-		
-	}
-
-}