Browse Source

[更新]ComposerUpdate

Anyon 6 years ago
parent
commit
8b2e4600b2
42 changed files with 840 additions and 199 deletions
  1. 6 3
      thinkphp/convention.php
  2. 41 26
      thinkphp/library/think/App.php
  3. 7 5
      thinkphp/library/think/Build.php
  4. 93 62
      thinkphp/library/think/Console.php
  5. 22 0
      thinkphp/library/think/Container.php
  6. 1 3
      thinkphp/library/think/Db.php
  7. 2 5
      thinkphp/library/think/Middleware.php
  8. 20 4
      thinkphp/library/think/Request.php
  9. 27 0
      thinkphp/library/think/Route.php
  10. 1 1
      thinkphp/library/think/Template.php
  11. 12 0
      thinkphp/library/think/console/Command.php
  12. 281 0
      thinkphp/library/think/console/Table.php
  13. 0 1
      thinkphp/library/think/console/command/Build.php
  14. 0 1
      thinkphp/library/think/console/command/Help.php
  15. 3 4
      thinkphp/library/think/console/command/Lists.php
  16. 2 3
      thinkphp/library/think/console/command/Make.php
  17. 130 0
      thinkphp/library/think/console/command/RouteList.php
  18. 0 1
      thinkphp/library/think/console/command/RunServer.php
  19. 0 1
      thinkphp/library/think/console/command/Version.php
  20. 56 0
      thinkphp/library/think/console/command/make/Command.php
  21. 0 1
      thinkphp/library/think/console/command/make/Controller.php
  22. 0 1
      thinkphp/library/think/console/command/make/Validate.php
  23. 24 0
      thinkphp/library/think/console/command/make/stubs/command.stub
  24. 5 5
      thinkphp/library/think/console/command/make/stubs/controller.api.stub
  25. 7 7
      thinkphp/library/think/console/command/make/stubs/controller.stub
  26. 0 1
      thinkphp/library/think/console/command/optimize/Autoload.php
  27. 0 3
      thinkphp/library/think/console/command/optimize/Config.php
  28. 1 4
      thinkphp/library/think/console/command/optimize/Route.php
  29. 0 3
      thinkphp/library/think/console/command/optimize/Schema.php
  30. 4 0
      thinkphp/library/think/console/output/descriptor/Console.php
  31. 20 3
      thinkphp/library/think/db/Connection.php
  32. 33 25
      thinkphp/library/think/db/Query.php
  33. 2 1
      thinkphp/library/think/route/Dispatch.php
  34. 8 3
      thinkphp/library/think/route/Resource.php
  35. 1 1
      thinkphp/library/think/route/Rule.php
  36. 5 1
      thinkphp/library/think/route/RuleGroup.php
  37. 6 0
      thinkphp/library/think/route/RuleItem.php
  38. 2 2
      thinkphp/library/think/route/RuleName.php
  39. 1 1
      vendor/autoload.php
  40. 7 7
      vendor/composer/autoload_real.php
  41. 4 4
      vendor/composer/autoload_static.php
  42. 6 6
      vendor/composer/installed.json

+ 6 - 3
thinkphp/convention.php

@@ -128,6 +128,8 @@ return [
         'route_check_cache'      => false,
         // 路由缓存的Key自定义设置(闭包),默认为当前URL和请求类型的md5
         'route_check_cache_key'  => '',
+        // 路由缓存的设置
+        'route_cache_option'     => [],
 
         // +----------------------------------------------------------------------
         // | 异常及错误设置
@@ -312,9 +314,10 @@ return [
 
     //控制台配置
     'console'    => [
-        'name'    => 'Think Console',
-        'version' => '0.1',
-        'user'    => null,
+        'name'      => 'Think Console',
+        'version'   => '0.1',
+        'user'      => null,
+        'auto_path' => '',
     ],
 
     // 中间件配置

+ 41 - 26
thinkphp/library/think/App.php

@@ -20,7 +20,7 @@ use think\route\Dispatch;
  */
 class App extends Container
 {
-    const VERSION = '5.1.23';
+    const VERSION = '5.1.24';
 
     /**
      * 当前模块路径
@@ -126,13 +126,8 @@ class App extends Container
 
     public function __construct($appPath = '')
     {
-        $this->appPath = $appPath ? realpath($appPath) . DIRECTORY_SEPARATOR : $this->getAppPath();
-
-        $this->thinkPath   = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR;
-        $this->rootPath    = dirname($this->appPath) . DIRECTORY_SEPARATOR;
-        $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
-        $this->routePath   = $this->rootPath . 'route' . DIRECTORY_SEPARATOR;
-        $this->configPath  = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
+        $this->thinkPath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR;
+        $this->path($appPath);
     }
 
     /**
@@ -155,7 +150,8 @@ class App extends Container
      */
     public function path($path)
     {
-        $this->appPath = $path;
+        $this->appPath = $path ? realpath($path) . DIRECTORY_SEPARATOR : $this->getAppPath();
+
         return $this;
     }
 
@@ -174,6 +170,11 @@ class App extends Container
         $this->beginTime   = microtime(true);
         $this->beginMem    = memory_get_usage();
 
+        $this->rootPath    = dirname($this->appPath) . DIRECTORY_SEPARATOR;
+        $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
+        $this->routePath   = $this->rootPath . 'route' . DIRECTORY_SEPARATOR;
+        $this->configPath  = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
+
         static::setInstance($this);
 
         $this->instance('app', $this);
@@ -484,17 +485,23 @@ class App extends Container
         $cache = $this->request->cache($key, $expire, $except, $tag);
 
         if ($cache) {
-            list($key, $expire, $tag) = $cache;
-            if (strtotime($this->request->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $this->request->server('REQUEST_TIME')) {
-                // 读取缓存
-                $response = Response::create()->code(304);
-                throw new HttpResponseException($response);
-            } elseif ($this->cache->has($key)) {
-                list($content, $header) = $this->cache->get($key);
-
-                $response = Response::create($content)->header($header);
-                throw new HttpResponseException($response);
-            }
+            $this->setResponseCache($cache);
+        }
+    }
+
+    public function setResponseCache($cache)
+    {
+        list($key, $expire, $tag) = $cache;
+
+        if (strtotime($this->request->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $this->request->server('REQUEST_TIME')) {
+            // 读取缓存
+            $response = Response::create()->code(304);
+            throw new HttpResponseException($response);
+        } elseif ($this->cache->has($key)) {
+            list($content, $header) = $this->cache->get($key);
+
+            $response = Response::create($content)->header($header);
+            throw new HttpResponseException($response);
         }
     }
 
@@ -578,10 +585,12 @@ class App extends Container
         // 检测路由缓存
         if (!$this->appDebug && $this->config->get('route_check_cache')) {
             $routeKey = $this->getRouteCacheKey();
-            $option   = $this->config->get('route_cache_option') ?: $this->cache->getConfig();
+            $option   = $this->config->get('route_cache_option');
 
-            if ($this->cache->connect($option)->has($routeKey)) {
+            if ($option && $this->cache->connect($option)->has($routeKey)) {
                 return $this->cache->connect($option)->get($routeKey);
+            } elseif ($this->cache->has($routeKey)) {
+                return $this->cache->get($routeKey);
             }
         }
 
@@ -596,10 +605,16 @@ class App extends Container
 
         if (!empty($routeKey)) {
             try {
-                $this->cache
-                    ->connect($option)
-                    ->tag('route_cache')
-                    ->set($routeKey, $dispatch);
+                if ($option) {
+                    $this->cache
+                        ->connect($option)
+                        ->tag('route_cache')
+                        ->set($routeKey, $dispatch);
+                } else {
+                    $this->cache
+                        ->tag('route_cache')
+                        ->set($routeKey, $dispatch);
+                }
             } catch (\Exception $e) {
                 // 存在闭包的时候缓存无效
             }

+ 7 - 5
thinkphp/library/think/Build.php

@@ -234,15 +234,17 @@ class Build
 
             $class = new \ReflectionClass($namespace . '\\' . $module . '\\' . $layer . '\\' . $controller);
 
-            if ($suffix) {
-                // 控制器后缀
-                $controller = substr($controller, 0, -strlen($layer));
-            }
-
             if (strpos($layer, '\\')) {
                 // 多级控制器
                 $level      = str_replace(DIRECTORY_SEPARATOR, '.', substr($layer, 11));
                 $controller = $level . '.' . $controller;
+                $length     = strlen(strstr($layer, '\\', true));
+            } else {
+                $length = strlen($layer);
+            }
+
+            if ($suffix) {
+                $controller = substr($controller, 0, -$length);
             }
 
             $content .= $this->getControllerRoute($class, $module, $controller);

+ 93 - 62
thinkphp/library/think/Console.php

@@ -35,20 +35,22 @@ class Console
     private $defaultCommand;
 
     private static $defaultCommands = [
-        "think\\console\\command\\Help",
-        "think\\console\\command\\Lists",
-        "think\\console\\command\\Build",
-        "think\\console\\command\\Clear",
-        "think\\console\\command\\make\\Controller",
-        "think\\console\\command\\make\\Model",
-        "think\\console\\command\\make\\Middleware",
-        "think\\console\\command\\make\\Validate",
-        "think\\console\\command\\optimize\\Autoload",
-        "think\\console\\command\\optimize\\Config",
-        "think\\console\\command\\optimize\\Schema",
-        "think\\console\\command\\optimize\\Route",
-        "think\\console\\command\\RunServer",
-        "think\\console\\command\\Version",
+        'help'              => "think\\console\\command\\Help",
+        'list'              => "think\\console\\command\\Lists",
+        'build'             => "think\\console\\command\\Build",
+        'clear'             => "think\\console\\command\\Clear",
+        'make:command'      => "think\\console\\command\\make\\Command",
+        'make:controller'   => "think\\console\\command\\make\\Controller",
+        'make:model'        => "think\\console\\command\\make\\Model",
+        'make:middleware'   => "think\\console\\command\\make\\Middleware",
+        'make:validate'     => "think\\console\\command\\make\\Validate",
+        'optimize:autoload' => "think\\console\\command\\optimize\\Autoload",
+        'optimize:config'   => "think\\console\\command\\optimize\\Config",
+        'optimize:schema'   => "think\\console\\command\\optimize\\Schema",
+        'optimize:route'    => "think\\console\\command\\optimize\\Route",
+        'run'               => "think\\console\\command\\RunServer",
+        'version'           => "think\\console\\command\\Version",
+        'route:list'        => "think\\console\\command\\RouteList",
     ];
 
     /**
@@ -69,10 +71,6 @@ class Console
 
         $this->defaultCommand = 'list';
         $this->definition     = $this->getDefaultInputDefinition();
-
-        foreach ($this->getDefaultCommands() as $command) {
-            $this->add($command);
-        }
     }
 
     /**
@@ -81,6 +79,10 @@ class Console
      */
     public function setUser($user)
     {
+        if (DIRECTORY_SEPARATOR == '\\') {
+            return;
+        }
+
         $user = posix_getpwnam($user);
         if ($user) {
             posix_setuid($user['uid']);
@@ -99,25 +101,13 @@ class Console
         static $console;
 
         if (!$console) {
-            $config = Container::get('config')->pull('console');
-            // 实例化 console
+            $config  = Container::get('config')->pull('console');
             $console = new self($config['name'], $config['version'], $config['user']);
 
-            // 读取指令集
-            $file = Container::get('env')->get('app_path') . 'command.php';
-
-            if (is_file($file)) {
-                $commands = include $file;
+            $commands = $console->getDefinedCommands($config);
 
-                if (is_array($commands)) {
-                    foreach ($commands as $command) {
-                        if (class_exists($command) && is_subclass_of($command, "\\think\\console\\Command")) {
-                            // 注册指令
-                            $console->add(new $command());
-                        }
-                    }
-                }
-            }
+            // 添加指令集
+            $console->addCommands($commands);
         }
 
         if ($run) {
@@ -130,6 +120,46 @@ class Console
 
     /**
      * @access public
+     * @param  array $config
+     * @return array
+     */
+    public function getDefinedCommands(array $config = [])
+    {
+        $commands = self::$defaultCommands;
+
+        if (!empty($config['auto_path']) && is_dir($config['auto_path'])) {
+            // 自动加载指令类
+            $files = scandir($config['auto_path']);
+
+            if (count($files) > 2) {
+                $beforeClass = get_declared_classes();
+
+                foreach ($files as $file) {
+                    if (pathinfo($file, PATHINFO_EXTENSION) == 'php') {
+                        include $config['auto_path'] . $file;
+                    }
+                }
+
+                $afterClass = get_declared_classes();
+                $commands   = array_merge($commands, array_diff($afterClass, $beforeClass));
+            }
+        }
+
+        $file = Container::get('env')->get('app_path') . 'command.php';
+
+        if (is_file($file)) {
+            $appCommands = include $file;
+
+            if (is_array($appCommands)) {
+                $commands = array_merge($commands, $appCommands);
+            }
+        }
+
+        return $commands;
+    }
+
+    /**
+     * @access public
      * @param  string $command
      * @param  array  $parameters
      * @param  string $driver
@@ -341,9 +371,9 @@ class Console
     }
 
     /**
-     * 注册一个指令
+     * 注册一个指令 (便于动态创建指令)
      * @access public
-     * @param  string $name
+     * @param  string $name     指令名
      * @return Command
      */
     public function register($name)
@@ -352,25 +382,38 @@ class Console
     }
 
     /**
-     * 添加指令
+     * 添加指令
      * @access public
-     * @param  Command[] $commands
+     * @param  array $commands
      */
     public function addCommands(array $commands)
     {
-        foreach ($commands as $command) {
-            $this->add($command);
+        foreach ($commands as $key => $command) {
+            if (is_subclass_of($command, "\\think\\console\\Command")) {
+                // 注册指令
+                $this->add($command, is_numeric($key) ? '' : $key);
+            }
         }
     }
 
     /**
-     * 添加一个指令
+     * 注册一个指令(对象)
      * @access public
-     * @param  Command $command
-     * @return Command
+     * @param  mixed    $command    指令对象或者指令类名
+     * @param  string   $name       指令名 留空则自动获取
+     * @return mixed
      */
-    public function add(Command $command)
+    public function add($command, $name)
     {
+        if ($name) {
+            $this->commands[$name] = $command;
+            return;
+        }
+
+        if (is_string($command)) {
+            $command = new $command();
+        }
+
         $command->setConsole($this);
 
         if (!$command->isEnabled()) {
@@ -406,6 +449,12 @@ class Console
 
         $command = $this->commands[$name];
 
+        if (is_string($command)) {
+            $command = new $command();
+        }
+
+        $command->setConsole($this);
+
         if ($this->wantHelps) {
             $this->wantHelps = false;
 
@@ -661,24 +710,6 @@ class Console
         ]);
     }
 
-    /**
-     * 设置默认命令
-     * @access protected
-     * @return Command[] An array of default Command instances
-     */
-    protected function getDefaultCommands()
-    {
-        $defaultCommands = [];
-
-        foreach (self::$defaultCommands as $classname) {
-            if (class_exists($classname) && is_subclass_of($classname, "think\\console\\Command")) {
-                $defaultCommands[] = new $classname();
-            }
-        }
-
-        return $defaultCommands;
-    }
-
     public static function addDefaultCommands(array $classnames)
     {
         self::$defaultCommands = array_merge(self::$defaultCommands, $classnames);

+ 22 - 0
thinkphp/library/think/Container.php

@@ -23,6 +23,28 @@ use ReflectionFunction;
 use ReflectionMethod;
 use think\exception\ClassNotFoundException;
 
+/**
+ * @package think
+ * @property Build          $build
+ * @property Cache          $cache
+ * @property Config         $config
+ * @property Cookie         $cookie
+ * @property Debug          $debug
+ * @property Env            $env
+ * @property Hook           $hook
+ * @property Lang           $lang
+ * @property Middleware     $middleware
+ * @property Request        $request
+ * @property Response       $response
+ * @property Route          $route
+ * @property Session        $session
+ * @property Template       $template
+ * @property Url            $url
+ * @property Validate       $validate
+ * @property View           $view
+ * @property route\RuleName $rule_name
+ * @property Log            $log
+ */
 class Container implements ArrayAccess, IteratorAggregate, Countable
 {
     /**

+ 1 - 3
thinkphp/library/think/Db.php

@@ -16,7 +16,6 @@ use think\db\Connection;
 /**
  * Class Db
  * @package think
- * @method \think\db\Query connect(array $config =[], mixed $name = false) static 连接/切换数据库连接
  * @method \think\db\Query master() static 从主服务器读取数据
  * @method \think\db\Query readMaster(bool $all = false) static 后续从主服务器读取数据
  * @method \think\db\Query table(string $table) static 指定数据表(含前缀)
@@ -35,7 +34,7 @@ use think\db\Connection;
  * @method \think\db\Query order(mixed $field, string $order = null) static 查询ORDER
  * @method \think\db\Query orderRaw(string $field, array $bind = []) static 查询ORDER
  * @method \think\db\Query cache(mixed $key = null , integer $expire = null) static 设置查询缓存
- * @method \think\db\Query withAttr(string $name = '',callable $callback) static 使用获取器获取数据
+ * @method \think\db\Query withAttr(string $name,callable $callback = null) static 使用获取器获取数据
  * @method mixed value(string $field) static 获取某个字段的值
  * @method array column(string $field, string $key = '') static 获取某个列的值
  * @method mixed find(mixed $data = null) static 查询单个记录
@@ -56,7 +55,6 @@ use think\db\Connection;
  * @method void rollback() static 事务回滚
  * @method boolean batchQuery(array $sqlArray) static 批处理执行SQL语句
  * @method string getLastInsID(string $sequence = null) static 获取最近插入的ID
- * @method mixed getConfig(string $name = '') static 获取数据库的配置参数
  */
 class Db
 {

+ 2 - 5
thinkphp/library/think/Middleware.php

@@ -113,13 +113,10 @@ class Middleware
     /**
      * 清除中间件
      * @access public
-     * @param  string $type  中间件类型
      */
-    public function clear($type = 'route')
+    public function clear()
     {
-        if (isset($this->queue[$type])) {
-            $this->queue[$type] = [];
-        }
+        $this->queue = [];
     }
 
     /**

+ 20 - 4
thinkphp/library/think/Request.php

@@ -1204,8 +1204,8 @@ class Request
                 $count = count($file['name']);
 
                 for ($i = 0; $i < $count; $i++) {
-                    if (empty($file['tmp_name'][$i]) || !is_file($file['tmp_name'][$i])) {
-                        continue;
+                    if ($file['error'][$i] > 0) {
+                        $this->throwUploadFileError($file['error'][$i]);
                     }
 
                     $temp['key'] = $key;
@@ -1222,8 +1222,8 @@ class Request
                 if ($file instanceof File) {
                     $array[$key] = $file;
                 } else {
-                    if (empty($file['tmp_name']) || !is_file($file['tmp_name'])) {
-                        continue;
+                    if ($file['error'] > 0) {
+                        $this->throwUploadFileError($file['error']);
                     }
 
                     $array[$key] = (new File($file['tmp_name']))->setUploadInfo($file);
@@ -1234,6 +1234,22 @@ class Request
         return $array;
     }
 
+    protected function throwUploadFileError($error)
+    {
+        static $fileUploadErrors = [
+            1 => 'upload File size exceeds the maximum value',
+            2 => 'upload File size exceeds the maximum value',
+            3 => 'only the portion of file is uploaded',
+            4 => 'no file to uploaded',
+            6 => 'upload temp dir not found',
+            7 => 'file write error',
+        ];
+
+        $msg = $fileUploadErrors[$error];
+
+        throw new Exception($msg);
+    }
+
     /**
      * 获取环境变量
      * @access public

+ 27 - 0
thinkphp/library/think/Route.php

@@ -114,6 +114,12 @@ class Route
     protected $lazy = true;
 
     /**
+     * 路由是否测试模式
+     * @var bool
+     */
+    protected $isTest;
+
+    /**
      * (分组)路由规则是否合并解析
      * @var bool
      */
@@ -192,6 +198,27 @@ class Route
     }
 
     /**
+     * 设置路由为测试模式
+     * @access public
+     * @param  bool     $test   路由是否测试模式
+     * @return void
+     */
+    public function setTestMode($test)
+    {
+        $this->isTest = $test;
+    }
+
+    /**
+     * 检查路由是否为测试模式
+     * @access public
+     * @return bool
+     */
+    public function isTest()
+    {
+        return $this->isTest;
+    }
+
+    /**
      * 设置路由域名及分组(包括资源路由)是否合并解析
      * @access public
      * @param  bool     $merge   路由是否合并解析

+ 1 - 1
thinkphp/library/think/Template.php

@@ -1050,7 +1050,7 @@ class Template
 
                 switch (strtolower($fun)) {
                     case 'raw':
-                        continue;
+                        break;
                     case 'date':
                         $name = 'date(' . $args[1] . ',!is_numeric(' . $name . ')? strtotime(' . $name . ') : ' . $name . ')';
                         break;

+ 12 - 0
thinkphp/library/think/console/Command.php

@@ -467,4 +467,16 @@ class Command
             throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
         }
     }
+
+    /**
+     * 输出表格
+     * @param Table $table
+     * @return string
+     */
+    protected function table(Table $table)
+    {
+        $content = $table->render();
+        $this->output->writeln($content);
+        return $content;
+    }
 }

+ 281 - 0
thinkphp/library/think/console/Table.php

@@ -0,0 +1,281 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: yunwuxin <448901948@qq.com>
+// +----------------------------------------------------------------------
+
+namespace think\console;
+
+class Table
+{
+    const ALIGN_LEFT   = 1;
+    const ALIGN_RIGHT  = 0;
+    const ALIGN_CENTER = 2;
+
+    /**
+     * 头信息数据
+     * @var array
+     */
+    protected $header = [];
+
+    /**
+     * 头部对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
+     * @var int
+     */
+    protected $headerAlign = 1;
+
+    /**
+     * 表格数据(二维数组)
+     * @var array
+     */
+    protected $rows = [];
+
+    /**
+     * 单元格对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
+     * @var int
+     */
+    protected $cellAlign = 1;
+
+    /**
+     * 单元格宽度信息
+     * @var array
+     */
+    protected $colWidth = [];
+
+    /**
+     * 表格输出样式
+     * @var string
+     */
+    protected $style = 'default';
+
+    /**
+     * 表格样式定义
+     * @var array
+     */
+    protected $format = [
+        'compact'    => [],
+        'default'    => [
+            'top'          => ['+', '-', '+', '+'],
+            'cell'         => ['|', ' ', '|', '|'],
+            'middle'       => ['+', '-', '+', '+'],
+            'bottom'       => ['+', '-', '+', '+'],
+            'cross-top'    => ['+', '-', '-', '+'],
+            'cross-bottom' => ['+', '-', '-', '+'],
+        ],
+        'markdown'   => [
+            'top'          => [' ', ' ', ' ', ' '],
+            'cell'         => ['|', ' ', '|', '|'],
+            'middle'       => ['|', '-', '|', '|'],
+            'bottom'       => [' ', ' ', ' ', ' '],
+            'cross-top'    => ['|', ' ', ' ', '|'],
+            'cross-bottom' => ['|', ' ', ' ', '|'],
+        ],
+        'borderless' => [
+            'top'          => ['=', '=', ' ', '='],
+            'cell'         => [' ', ' ', ' ', ' '],
+            'middle'       => ['=', '=', ' ', '='],
+            'bottom'       => ['=', '=', ' ', '='],
+            'cross-top'    => ['=', '=', ' ', '='],
+            'cross-bottom' => ['=', '=', ' ', '='],
+        ],
+        'box'        => [
+            'top'          => ['┌', '─', '┬', '┐'],
+            'cell'         => ['│', ' ', '│', '│'],
+            'middle'       => ['├', '─', '┼', '┤'],
+            'bottom'       => ['└', '─', '┴', '┘'],
+            'cross-top'    => ['├', '─', '┴', '┤'],
+            'cross-bottom' => ['├', '─', '┬', '┤'],
+        ],
+        'box-double' => [
+            'top'          => ['╔', '═', '╤', '╗'],
+            'cell'         => ['║', ' ', '│', '║'],
+            'middle'       => ['╠', '─', '╪', '╣'],
+            'bottom'       => ['╚', '═', '╧', '╝'],
+            'cross-top'    => ['╠', '═', '╧', '╣'],
+            'cross-bottom' => ['╠', '═', '╤', '╣'],
+        ],
+    ];
+
+    /**
+     * 设置表格头信息 以及对齐方式
+     * @access public
+     * @param array $header     要输出的Header信息
+     * @param int   $align      对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
+     * @return void
+     */
+    public function setHeader(array $header, $align = self::ALIGN_LEFT)
+    {
+        $this->header      = $header;
+        $this->headerAlign = $align;
+
+        $this->checkColWidth($header);
+    }
+
+    /**
+     * 设置输出表格数据 及对齐方式
+     * @access public
+     * @param array $rows       要输出的表格数据(二维数组)
+     * @param int   $align      对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
+     * @return void
+     */
+    public function setRows(array $rows, $align = self::ALIGN_LEFT)
+    {
+        $this->rows      = $rows;
+        $this->cellAlign = $align;
+
+        foreach ($rows as $row) {
+            $this->checkColWidth($row);
+        }
+    }
+
+    /**
+     * 检查列数据的显示宽度
+     * @access public
+     * @param  mixed $row       行数据
+     * @return void
+     */
+    protected function checkColWidth($row)
+    {
+        if (is_array($row)) {
+            foreach ($row as $key => $cell) {
+                if (!isset($this->colWidth[$key]) || strlen($cell) > $this->colWidth[$key]) {
+                    $this->colWidth[$key] = strlen($cell);
+                }
+            }
+        }
+    }
+
+    /**
+     * 增加一行表格数据
+     * @access public
+     * @param  mixed $row       行数据
+     * @param  bool  $first     是否在开头插入
+     * @return void
+     */
+    public function addRow($row, $first = false)
+    {
+        if ($first) {
+            array_unshift($this->rows, $row);
+        } else {
+            $this->rows[] = $row;
+        }
+
+        $this->checkColWidth($row);
+    }
+
+    /**
+     * 设置输出表格的样式
+     * @access public
+     * @param  string $style       样式名
+     * @return void
+     */
+    public function setStyle($style)
+    {
+        $this->style = isset($this->format[$style]) ? $style : 'default';
+    }
+
+    /**
+     * 输出分隔行
+     * @access public
+     * @param  string $pos       位置
+     * @return string
+     */
+    protected function renderSeparator($pos)
+    {
+        $style = $this->getStyle($pos);
+        $array = [];
+
+        foreach ($this->colWidth as $width) {
+            $array[] = str_repeat($style[1], $width + 2);
+        }
+
+        return $style[0] . implode($style[2], $array) . $style[3] . PHP_EOL;
+    }
+
+    /**
+     * 输出表格头部
+     * @access public
+     * @return string
+     */
+    protected function renderHeader()
+    {
+        $style   = $this->getStyle('cell');
+        $content = $this->renderSeparator('top');
+
+        foreach ($this->header as $key => $header) {
+            $array[] = ' ' . str_pad($header, $this->colWidth[$key], $style[1], $this->headerAlign);
+        }
+
+        if (!empty($array)) {
+            $content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
+
+            if ($this->rows) {
+                $content .= $this->renderSeparator('middle');
+            }
+        }
+
+        return $content;
+    }
+
+    protected function getStyle($style)
+    {
+        if ($this->format[$this->style]) {
+            $style = $this->format[$this->style][$style];
+        } else {
+            $style = [' ', ' ', ' ', ' '];
+        }
+
+        return $style;
+    }
+
+    /**
+     * 输出表格
+     * @access public
+     * @param  array $dataList       表格数据
+     * @return string
+     */
+    public function render($dataList = [])
+    {
+        if ($dataList) {
+            $this->setRows($dataList);
+        }
+
+        // 输出头部
+        $content = $this->renderHeader();
+        $style   = $this->getStyle('cell');
+
+        if ($this->rows) {
+            foreach ($this->rows as $row) {
+                if (is_string($row) && '-' === $row) {
+                    $content .= $this->renderSeparator('middle');
+                } elseif (is_scalar($row)) {
+                    $content .= $this->renderSeparator('cross-top');
+                    $array = str_pad($row, 3 * (count($this->colWidth) - 1) + array_reduce($this->colWidth, function ($a, $b) {
+                        return $a + $b;
+                    }));
+
+                    $content .= $style[0] . ' ' . $array . ' ' . $style[3] . PHP_EOL;
+                    $content .= $this->renderSeparator('cross-bottom');
+                } else {
+                    $array = [];
+
+                    foreach ($row as $key => $val) {
+                        $array[] = ' ' . str_pad($val, $this->colWidth[$key], ' ', $this->cellAlign);
+                    }
+
+                    $content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
+
+                }
+            }
+        }
+
+        $content .= $this->renderSeparator('bottom');
+
+        return $content;
+    }
+}

+ 0 - 1
thinkphp/library/think/console/command/Build.php

@@ -20,7 +20,6 @@ use think\facade\Build as AppBuild;
 
 class Build extends Command
 {
-
     /**
      * {@inheritdoc}
      */

+ 0 - 1
thinkphp/library/think/console/command/Help.php

@@ -19,7 +19,6 @@ use think\console\Output;
 
 class Help extends Command
 {
-
     private $command;
 
     /**

+ 3 - 4
thinkphp/library/think/console/command/Lists.php

@@ -13,14 +13,13 @@ namespace think\console\command;
 
 use think\console\Command;
 use think\console\Input;
-use think\console\Output;
 use think\console\input\Argument as InputArgument;
-use think\console\input\Option as InputOption;
 use think\console\input\Definition as InputDefinition;
+use think\console\input\Option as InputOption;
+use think\console\Output;
 
 class Lists extends Command
 {
-
     /**
      * {@inheritdoc}
      */
@@ -68,7 +67,7 @@ EOF
     {
         return new InputDefinition([
             new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
-            new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list')
+            new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
         ]);
     }
 }

+ 2 - 3
thinkphp/library/think/console/command/Make.php

@@ -21,7 +21,6 @@ use think\facade\Env;
 
 abstract class Make extends Command
 {
-
     protected $type;
 
     abstract protected function getStub();
@@ -63,12 +62,12 @@ abstract class Make extends Command
 
         $class = str_replace($namespace . '\\', '', $name);
 
-        return str_replace(['{%className%}', '{%namespace%}', '{%app_namespace%}'], [
+        return str_replace(['{%className%}', '{%actionSuffix%}', '{%namespace%}', '{%app_namespace%}'], [
             $class,
+            Config::get('action_suffix'),
             $namespace,
             App::getNamespace(),
         ], $stub);
-
     }
 
     protected function getPathName($name)

+ 130 - 0
thinkphp/library/think/console/command/RouteList.php

@@ -0,0 +1,130 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: yunwuxin <448901948@qq.com>
+// +----------------------------------------------------------------------
+namespace think\console\command;
+
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Argument;
+use think\console\input\Option;
+use think\console\Output;
+use think\console\Table;
+use think\Container;
+
+class RouteList extends Command
+{
+    protected $sortBy = [
+        'rule'   => 0,
+        'route'  => 1,
+        'method' => 2,
+        'name'   => 3,
+        'domain' => 4,
+    ];
+
+    protected function configure()
+    {
+        $this->setName('route:list')
+            ->addArgument('style', Argument::OPTIONAL, "the style of the table.", 'default')
+            ->addOption('sort', 's', Option::VALUE_OPTIONAL, 'order by rule name.', 0)
+            ->addOption('more', 'm', Option::VALUE_NONE, 'show route options.')
+            ->setDescription('show route list.');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $filename = Container::get('app')->getRuntimePath() . 'route_list.php';
+
+        if (is_file($filename)) {
+            unlink($filename);
+        }
+
+        $content = $this->getRouteList();
+        file_put_contents($filename, 'Route List' . PHP_EOL . $content);
+    }
+
+    protected function getRouteList()
+    {
+        Container::get('route')->setTestMode(true);
+        // 路由检测
+        $path = Container::get('app')->getRoutePath();
+
+        $files = is_dir($path) ? scandir($path) : [];
+
+        foreach ($files as $file) {
+            if (strpos($file, '.php')) {
+                $filename = $path . DIRECTORY_SEPARATOR . $file;
+                // 导入路由配置
+                $rules = include $filename;
+
+                if (is_array($rules)) {
+                    Container::get('route')->import($rules);
+                }
+            }
+        }
+
+        if (Container::get('config')->get('route_annotation')) {
+            $suffix = Container::get('config')->get('controller_suffix') || Container::get('config')->get('class_suffix');
+
+            include Container::get('build')->buildRoute($suffix);
+        }
+
+        $table = new Table();
+
+        if ($this->input->hasOption('more')) {
+            $header = ['Rule', 'Route', 'Method', 'Name', 'Domain', 'Option', 'Pattern'];
+        } else {
+            $header = ['Rule', 'Route', 'Method', 'Name', 'Domain'];
+        }
+
+        $table->setHeader($header);
+
+        $routeList = Container::get('route')->getRuleList();
+        $rows      = [];
+
+        foreach ($routeList as $domain => $items) {
+            foreach ($items as $item) {
+                $item['route'] = $item['route'] instanceof \Closure ? '<Closure>' : $item['route'];
+
+                if ($this->input->hasOption('more')) {
+                    $item = [$item['rule'], $item['route'], $item['method'], $item['name'], $domain, json_encode($item['option']), json_encode($item['pattern'])];
+                } else {
+                    $item = [$item['rule'], $item['route'], $item['method'], $item['name'], $domain];
+                }
+
+                $rows[] = $item;
+            }
+        }
+
+        if ($this->input->getOption('sort')) {
+            $sort = $this->input->getOption('sort');
+
+            if (isset($this->sortBy[$sort])) {
+                $sort = $this->sortBy[$sort];
+            }
+
+            uasort($rows, function ($a, $b) use ($sort) {
+                $itemA = isset($a[$sort]) ? $a[$sort] : null;
+                $itemB = isset($b[$sort]) ? $b[$sort] : null;
+
+                return strcasecmp($itemA, $itemB);
+            });
+        }
+
+        $table->setRows($rows);
+
+        if ($this->input->getArgument('style')) {
+            $style = $this->input->getArgument('style');
+            $table->setStyle($style);
+        }
+
+        return $this->table($table);
+    }
+
+}

+ 0 - 1
thinkphp/library/think/console/command/RunServer.php

@@ -18,7 +18,6 @@ use think\facade\App;
 
 class RunServer extends Command
 {
-
     public function configure()
     {
         $this->setName('run')

+ 0 - 1
thinkphp/library/think/console/command/Version.php

@@ -28,5 +28,4 @@ class Version extends Command
     {
         $output->writeln('v' . App::version());
     }
-
 }

+ 56 - 0
thinkphp/library/think/console/command/make/Command.php

@@ -0,0 +1,56 @@
+<?php
+// +----------------------------------------------------------------------
+// | ThinkPHP [ WE CAN DO IT JUST THINK ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016 http://thinkphp.cn All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+// +----------------------------------------------------------------------
+// | Author: 刘志淳 <chun@engineer.com>
+// +----------------------------------------------------------------------
+
+namespace think\console\command\make;
+
+use think\console\command\Make;
+use think\console\input\Argument;
+use think\facade\App;
+
+class Command extends Make
+{
+    protected $type = "Command";
+
+    protected function configure()
+    {
+        parent::configure();
+        $this->setName('make:command')
+            ->addArgument('commandName', Argument::OPTIONAL, "The name of the command")
+            ->setDescription('Create a new command class');
+    }
+
+    protected function buildClass($name)
+    {
+        $commandName = $this->input->getArgument('commandName') ?: strtolower(basename($name));
+        $namespace   = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
+
+        $class = str_replace($namespace . '\\', '', $name);
+        $stub  = file_get_contents($this->getStub());
+
+        return str_replace(['{%commandName%}', '{%className%}', '{%namespace%}', '{%app_namespace%}'], [
+            $commandName,
+            $class,
+            $namespace,
+            App::getNamespace(),
+        ], $stub);
+    }
+
+    protected function getStub()
+    {
+        return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'command.stub';
+    }
+
+    protected function getNamespace($appNamespace, $module)
+    {
+        return $appNamespace . '\\command';
+    }
+
+}

+ 0 - 1
thinkphp/library/think/console/command/make/Controller.php

@@ -17,7 +17,6 @@ use think\facade\Config;
 
 class Controller extends Make
 {
-
     protected $type = "Controller";
 
     protected function configure()

+ 0 - 1
thinkphp/library/think/console/command/make/Validate.php

@@ -15,7 +15,6 @@ use think\console\command\Make;
 
 class Validate extends Make
 {
-
     protected $type = "Validate";
 
     protected function configure()

+ 24 - 0
thinkphp/library/think/console/command/make/stubs/command.stub

@@ -0,0 +1,24 @@
+<?php
+
+namespace {%namespace%};
+
+use think\console\Command;
+use think\console\Input;
+use think\console\Output;
+
+class {%className%} extends Command
+{
+    protected function configure()
+    {
+        // 指令配置
+        $this->setName('{%commandName%}');
+        // 设置参数
+        
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+    	// 指令输出
+    	$output->writeln('{%commandName%}');
+    }
+}

+ 5 - 5
thinkphp/library/think/console/command/make/stubs/controller.api.stub

@@ -12,7 +12,7 @@ class {%className%} extends Controller
      *
      * @return \think\Response
      */
-    public function index()
+    public function index{%actionSuffix%}()
     {
         //
     }
@@ -23,7 +23,7 @@ class {%className%} extends Controller
      * @param  \think\Request  $request
      * @return \think\Response
      */
-    public function save(Request $request)
+    public function save{%actionSuffix%}(Request $request)
     {
         //
     }
@@ -34,7 +34,7 @@ class {%className%} extends Controller
      * @param  int  $id
      * @return \think\Response
      */
-    public function read($id)
+    public function read{%actionSuffix%}($id)
     {
         //
     }
@@ -46,7 +46,7 @@ class {%className%} extends Controller
      * @param  int  $id
      * @return \think\Response
      */
-    public function update(Request $request, $id)
+    public function update{%actionSuffix%}(Request $request, $id)
     {
         //
     }
@@ -57,7 +57,7 @@ class {%className%} extends Controller
      * @param  int  $id
      * @return \think\Response
      */
-    public function delete($id)
+    public function delete{%actionSuffix%}($id)
     {
         //
     }

+ 7 - 7
thinkphp/library/think/console/command/make/stubs/controller.stub

@@ -12,7 +12,7 @@ class {%className%} extends Controller
      *
      * @return \think\Response
      */
-    public function index()
+    public function index{%actionSuffix%}()
     {
         //
     }
@@ -22,7 +22,7 @@ class {%className%} extends Controller
      *
      * @return \think\Response
      */
-    public function create()
+    public function create{%actionSuffix%}()
     {
         //
     }
@@ -33,7 +33,7 @@ class {%className%} extends Controller
      * @param  \think\Request  $request
      * @return \think\Response
      */
-    public function save(Request $request)
+    public function save{%actionSuffix%}(Request $request)
     {
         //
     }
@@ -44,7 +44,7 @@ class {%className%} extends Controller
      * @param  int  $id
      * @return \think\Response
      */
-    public function read($id)
+    public function read{%actionSuffix%}($id)
     {
         //
     }
@@ -55,7 +55,7 @@ class {%className%} extends Controller
      * @param  int  $id
      * @return \think\Response
      */
-    public function edit($id)
+    public function edit{%actionSuffix%}($id)
     {
         //
     }
@@ -67,7 +67,7 @@ class {%className%} extends Controller
      * @param  int  $id
      * @return \think\Response
      */
-    public function update(Request $request, $id)
+    public function update{%actionSuffix%}(Request $request, $id)
     {
         //
     }
@@ -78,7 +78,7 @@ class {%className%} extends Controller
      * @param  int  $id
      * @return \think\Response
      */
-    public function delete($id)
+    public function delete{%actionSuffix%}($id)
     {
         //
     }

+ 0 - 1
thinkphp/library/think/console/command/optimize/Autoload.php

@@ -17,7 +17,6 @@ use think\Container;
 
 class Autoload extends Command
 {
-
     protected function configure()
     {
         $this->setName('optimize:autoload')

+ 0 - 3
thinkphp/library/think/console/command/optimize/Config.php

@@ -19,9 +19,6 @@ use think\facade\App;
 
 class Config extends Command
 {
-    /** @var  Output */
-    protected $output;
-
     protected function configure()
     {
         $this->setName('optimize:config')

+ 1 - 4
thinkphp/library/think/console/command/optimize/Route.php

@@ -17,9 +17,6 @@ use think\Container;
 
 class Route extends Command
 {
-    /** @var  Output */
-    protected $output;
-
     protected function configure()
     {
         $this->setName('optimize:route')
@@ -39,7 +36,7 @@ class Route extends Command
     protected function buildRouteCache()
     {
         Container::get('route')->setName([]);
-        Container::get('route')->lazy(false);
+        Container::get('route')->setTestMode(true);
         // 路由检测
         $path = Container::get('app')->getRoutePath();
 

+ 0 - 3
thinkphp/library/think/console/command/optimize/Schema.php

@@ -19,9 +19,6 @@ use think\facade\App;
 
 class Schema extends Command
 {
-    /** @var  Output */
-    protected $output;
-
     protected function configure()
     {
         $this->setName('optimize:schema')

+ 4 - 0
thinkphp/library/think/console/output/descriptor/Console.php

@@ -104,6 +104,10 @@ class Console
 
             /** @var Command $command */
             foreach ($commands as $name => $command) {
+                if (is_string($command)) {
+                    $command = new $command();
+                }
+
                 if (!$command->getName()) {
                     continue;
                 }

+ 20 - 3
thinkphp/library/think/db/Connection.php

@@ -323,9 +323,8 @@ abstract class Connection
     public function parseSqlTable($sql)
     {
         if (false !== strpos($sql, '__')) {
-            $prefix = $this->getConfig('prefix');
-            $sql    = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function ($match) use ($prefix) {
-                return $prefix . strtolower($match[1]);
+            $sql = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function ($match) {
+                return $this->getConfig('prefix') . strtolower($match[1]);
             }, $sql);
         }
 
@@ -825,6 +824,8 @@ abstract class Connection
         // 生成查询SQL
         $sql = $this->builder->select($query);
 
+        $query->removeOption('limit');
+
         $bind = $query->getBind();
 
         if (!empty($options['fetch_sql'])) {
@@ -903,6 +904,8 @@ abstract class Connection
         // 生成查询SQL
         $sql = $this->builder->select($query);
 
+        $query->removeOption('limit');
+
         $bind = $query->getBind();
 
         if (!empty($options['fetch_sql'])) {
@@ -1270,6 +1273,14 @@ abstract class Connection
         // 生成查询SQL
         $sql = $this->builder->select($query);
 
+        if (isset($options['field'])) {
+            $query->setOption('field', $options['field']);
+        } else {
+            $query->removeOption('field');
+        }
+
+        $query->removeOption('limit');
+
         $bind = $query->getBind();
 
         if (!empty($options['fetch_sql'])) {
@@ -1346,6 +1357,12 @@ abstract class Connection
         // 生成查询SQL
         $sql = $this->builder->select($query);
 
+        if (isset($options['field'])) {
+            $query->setOption('field', $options['field']);
+        } else {
+            $query->removeOption('field');
+        }
+
         $bind = $query->getBind();
 
         if (!empty($options['fetch_sql'])) {

+ 33 - 25
thinkphp/library/think/db/Query.php

@@ -151,7 +151,8 @@ class Query
             // 调用扩展查询方法
             array_unshift($args, $this);
 
-            return Container::getInstance()->invoke(self::$extend[strtolower($method)], $args);
+            return Container::getInstance()
+                ->invoke(self::$extend[strtolower($method)], $args);
         } elseif (strtolower(substr($method, 0, 5)) == 'getby') {
             // 根据某个字段获取记录
             $field = Loader::parseName(substr($method, 5));
@@ -304,14 +305,14 @@ class Query
      * @param  string      $sql    sql指令
      * @param  array       $bind   参数绑定
      * @param  boolean     $master 是否在主服务器读操作
-     * @param  bool|string $class  指定返回的数据集对象
+     * @param  bool        $pdo    是否返回PDO对象
      * @return mixed
      * @throws BindParamException
      * @throws PDOException
      */
-    public function query($sql, $bind = [], $master = false, $class = false)
+    public function query($sql, $bind = [], $master = false, $pdo = false)
     {
-        return $this->connection->query($sql, $bind, $master, $class);
+        return $this->connection->query($sql, $bind, $master, $pdo);
     }
 
     /**
@@ -641,7 +642,10 @@ class Query
         if (!empty($this->options['group'])) {
             // 支持GROUP
             $options = $this->getOptions();
-            $subSql  = $this->options($options)->field('count(' . $field . ') AS think_count')->bind($this->bind)->buildSql();
+            $subSql  = $this->options($options)
+                ->field('count(' . $field . ') AS think_count')
+                ->bind($this->bind)
+                ->buildSql();
 
             $query = $this->newQuery()->table([$subSql => '_group_count_']);
 
@@ -1187,19 +1191,6 @@ class Query
     }
 
     /**
-     * 设置是否返回数据集对象
-     * @access public
-     * @param  bool  $collection  是否返回数据集对象
-     * @return $this
-     */
-    public function fetchCollection($collection = true)
-    {
-        $this->options['collection'] = $collection;
-
-        return $this;
-    }
-
-    /**
      * 指定AND查询条件
      * @access public
      * @param  mixed $field     查询字段
@@ -1763,6 +1754,9 @@ class Query
             $results = $this->page($page, $listRows)->select();
         }
 
+        $this->removeOption('limit');
+        $this->removeOption('page');
+
         return $class::make($results, $listRows, $page, $total, $simple, $config);
     }
 
@@ -2080,6 +2074,19 @@ class Query
     }
 
     /**
+     * 设置是否返回数据集对象(支持设置数据集对象类名)
+     * @access public
+     * @param  bool|string  $collection  是否返回数据集对象
+     * @return $this
+     */
+    public function fetchCollection($collection = true)
+    {
+        $this->options['collection'] = $collection;
+
+        return $this;
+    }
+
+    /**
      * 设置从主服务器读取数据
      * @access public
      * @return $this
@@ -2283,7 +2290,8 @@ class Query
                 $field($this, isset($data[$key]) ? $data[$key] : null, $data, $prefix);
             } elseif ($this->model) {
                 // 检测搜索器
-                $method = 'search' . Loader::parseName($field, 1) . 'Attr';
+                $fieldName = is_numeric($key) ? $field : $key;
+                $method    = 'search' . Loader::parseName($fieldName, 1) . 'Attr';
 
                 if (method_exists($this->model, $method)) {
                     $this->model->$method($this, isset($data[$field]) ? $data[$field] : null, $data, $prefix);
@@ -2986,8 +2994,12 @@ class Query
      */
     protected function resultSetToModelCollection(array $resultSet)
     {
+        if (!empty($this->options['collection']) && is_string($this->options['collection'])) {
+            $collection = $this->options['collection'];
+        }
+
         if (empty($resultSet)) {
-            return $this->model->toCollection([]);
+            return $this->model->toCollection([], isset($collection) ? $collection : null);
         }
 
         // 检查动态获取器
@@ -3020,7 +3032,7 @@ class Query
         }
 
         // 模型数据集转换
-        return $result->toCollection($resultSet);
+        return $result->toCollection($resultSet, isset($collection) ? $collection : null);
     }
 
     /**
@@ -3082,8 +3094,6 @@ class Query
             return $result;
         }
 
-        $this->removeOption('limit');
-
         // 数据处理
         if (empty($result)) {
             return $this->resultToEmpty();
@@ -3113,8 +3123,6 @@ class Query
             return !empty($this->model) ? $this->model->newInstance([], $this->getModelUpdateCondition($this->options)) : [];
         } elseif (!empty($this->options['fail'])) {
             $this->throwNotFound($this->options);
-        } else {
-            return;
         }
     }
 

+ 2 - 1
thinkphp/library/think/route/Dispatch.php

@@ -273,7 +273,8 @@ abstract class Dispatch
             $tag    = null;
         }
 
-        $this->request->cache($key, $expire, $tag);
+        $cache = $this->request->cache($key, $expire, $tag);
+        $this->app->setResponseCache($cache);
     }
 
     /**

+ 8 - 3
thinkphp/library/think/route/Resource.php

@@ -53,20 +53,25 @@ class Resource extends RuleGroup
             $this->domain = $this->parent->getDomain();
             $this->parent->addRuleItem($this);
         }
+
+        if ($router->isTest()) {
+            $this->buildResourceRule();
+        }
     }
 
     /**
      * 生成资源路由规则
      * @access protected
-     * @param  string    $rule       路由规则
-     * @param  array     $option     路由参数
      * @return void
      */
-    protected function buildResourceRule($rule, $option = [])
+    protected function buildResourceRule()
     {
         $origin = $this->router->getGroup();
         $this->router->setGroup($this);
 
+        $rule   = $this->resource;
+        $option = $this->option;
+
         if (strpos($rule, '.')) {
             // 注册嵌套资源路由
             $array = explode('.', $rule);

+ 1 - 1
thinkphp/library/think/route/Rule.php

@@ -682,7 +682,7 @@ abstract class Rule
     /**
      * 合并分组参数
      * @access protected
-     * @return void
+     * @return array
      */
     protected function mergeGroupOptions()
     {

+ 5 - 1
thinkphp/library/think/route/RuleGroup.php

@@ -74,6 +74,10 @@ class RuleGroup extends Rule
         if (!empty($option['cross_domain'])) {
             $this->router->setCrossDomainRule($this);
         }
+
+        if ($router->isTest()) {
+            $this->lazy(false);
+        }
     }
 
     /**
@@ -134,7 +138,7 @@ class RuleGroup extends Rule
 
         // 解析分组路由
         if ($this instanceof Resource) {
-            $this->buildResourceRule($this->resource, $this->option);
+            $this->buildResourceRule();
         } elseif ($this->rule) {
             if ($this->rule instanceof Response) {
                 return new ResponseDispatch($request, $this, $this->rule);

+ 6 - 0
thinkphp/library/think/route/RuleItem.php

@@ -17,6 +17,8 @@ use think\Route;
 
 class RuleItem extends Rule
 {
+    protected $hasSetRule;
+
     /**
      * 架构函数
      * @access public
@@ -128,7 +130,11 @@ class RuleItem extends Rule
             $value = [$this->rule, $vars, $this->parent->getDomain(), $suffix, $this->method];
 
             Container::get('rule_name')->set($name, $value, $first);
+        }
+
+        if (!$this->hasSetRule) {
             Container::get('rule_name')->setRule($this->rule, $this);
+            $this->hasSetRule = true;
         }
     }
 

+ 2 - 2
thinkphp/library/think/route/RuleName.php

@@ -42,7 +42,7 @@ class RuleName
      */
     public function setRule($rule, $route)
     {
-        $this->rule[$route->getDomain()][$rule][$route->getRoute()] = $route;
+        $this->rule[$route->getDomain()][$rule][$route->getMethod()] = $route;
     }
 
     /**
@@ -70,7 +70,7 @@ class RuleName
         foreach ($this->rule as $ruleDomain => $rules) {
             foreach ($rules as $rule => $items) {
                 foreach ($items as $item) {
-                    $val = [];
+                    $val['domain'] = $ruleDomain;
 
                     foreach (['method', 'rule', 'name', 'route', 'pattern', 'option'] as $param) {
                         $call        = 'get' . $param;

+ 1 - 1
vendor/autoload.php

@@ -4,4 +4,4 @@
 
 require_once __DIR__ . '/composer/autoload_real.php';
 
-return ComposerAutoloaderInit1fe0085f96d2ca8d2e2a2e50651b591c::getLoader();
+return ComposerAutoloaderInit1d3094fd985c01a522304485af2b5f26::getLoader();

+ 7 - 7
vendor/composer/autoload_real.php

@@ -2,7 +2,7 @@
 
 // autoload_real.php @generated by Composer
 
-class ComposerAutoloaderInit1fe0085f96d2ca8d2e2a2e50651b591c
+class ComposerAutoloaderInit1d3094fd985c01a522304485af2b5f26
 {
     private static $loader;
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit1fe0085f96d2ca8d2e2a2e50651b591c
             return self::$loader;
         }
 
-        spl_autoload_register(array('ComposerAutoloaderInit1fe0085f96d2ca8d2e2a2e50651b591c', 'loadClassLoader'), true, true);
+        spl_autoload_register(array('ComposerAutoloaderInit1d3094fd985c01a522304485af2b5f26', 'loadClassLoader'), true, true);
         self::$loader = $loader = new \Composer\Autoload\ClassLoader();
-        spl_autoload_unregister(array('ComposerAutoloaderInit1fe0085f96d2ca8d2e2a2e50651b591c', 'loadClassLoader'));
+        spl_autoload_unregister(array('ComposerAutoloaderInit1d3094fd985c01a522304485af2b5f26', 'loadClassLoader'));
 
         $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
         if ($useStaticLoader) {
             require_once __DIR__ . '/autoload_static.php';
 
-            call_user_func(\Composer\Autoload\ComposerStaticInit1fe0085f96d2ca8d2e2a2e50651b591c::getInitializer($loader));
+            call_user_func(\Composer\Autoload\ComposerStaticInit1d3094fd985c01a522304485af2b5f26::getInitializer($loader));
         } else {
             $map = require __DIR__ . '/autoload_namespaces.php';
             foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInit1fe0085f96d2ca8d2e2a2e50651b591c
         $loader->register(true);
 
         if ($useStaticLoader) {
-            $includeFiles = Composer\Autoload\ComposerStaticInit1fe0085f96d2ca8d2e2a2e50651b591c::$files;
+            $includeFiles = Composer\Autoload\ComposerStaticInit1d3094fd985c01a522304485af2b5f26::$files;
         } else {
             $includeFiles = require __DIR__ . '/autoload_files.php';
         }
         foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequire1fe0085f96d2ca8d2e2a2e50651b591c($fileIdentifier, $file);
+            composerRequire1d3094fd985c01a522304485af2b5f26($fileIdentifier, $file);
         }
 
         return $loader;
     }
 }
 
-function composerRequire1fe0085f96d2ca8d2e2a2e50651b591c($fileIdentifier, $file)
+function composerRequire1d3094fd985c01a522304485af2b5f26($fileIdentifier, $file)
 {
     if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
         require $file;

+ 4 - 4
vendor/composer/autoload_static.php

@@ -4,7 +4,7 @@
 
 namespace Composer\Autoload;
 
-class ComposerStaticInit1fe0085f96d2ca8d2e2a2e50651b591c
+class ComposerStaticInit1d3094fd985c01a522304485af2b5f26
 {
     public static $files = array (
         '1cfd2761b63b0a29ed23657ea394cb2d' => __DIR__ . '/..' . '/topthink/think-captcha/src/helper.php',
@@ -303,9 +303,9 @@ class ComposerStaticInit1fe0085f96d2ca8d2e2a2e50651b591c
     public static function getInitializer(ClassLoader $loader)
     {
         return \Closure::bind(function () use ($loader) {
-            $loader->prefixLengthsPsr4 = ComposerStaticInit1fe0085f96d2ca8d2e2a2e50651b591c::$prefixLengthsPsr4;
-            $loader->prefixDirsPsr4 = ComposerStaticInit1fe0085f96d2ca8d2e2a2e50651b591c::$prefixDirsPsr4;
-            $loader->classMap = ComposerStaticInit1fe0085f96d2ca8d2e2a2e50651b591c::$classMap;
+            $loader->prefixLengthsPsr4 = ComposerStaticInit1d3094fd985c01a522304485af2b5f26::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = ComposerStaticInit1d3094fd985c01a522304485af2b5f26::$prefixDirsPsr4;
+            $loader->classMap = ComposerStaticInit1d3094fd985c01a522304485af2b5f26::$classMap;
 
         }, null, ClassLoader::class);
     }

+ 6 - 6
vendor/composer/installed.json

@@ -50,17 +50,17 @@
     },
     {
         "name": "topthink/framework",
-        "version": "v5.1.23",
-        "version_normalized": "5.1.23.0",
+        "version": "v5.1.24",
+        "version_normalized": "5.1.24.0",
         "source": {
             "type": "git",
             "url": "https://github.com/top-think/framework.git",
-            "reference": "7b7f1b6b23897e7f0c7a98a56e61723a61fa27ce"
+            "reference": "03ee17d1ea9c432a698fa1d2411df53974420187"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/top-think/framework/zipball/7b7f1b6b23897e7f0c7a98a56e61723a61fa27ce",
-            "reference": "7b7f1b6b23897e7f0c7a98a56e61723a61fa27ce",
+            "url": "https://api.github.com/repos/top-think/framework/zipball/03ee17d1ea9c432a698fa1d2411df53974420187",
+            "reference": "03ee17d1ea9c432a698fa1d2411df53974420187",
             "shasum": "",
             "mirrors": [
                 {
@@ -82,7 +82,7 @@
             "sebastian/phpcpd": "2.*",
             "squizlabs/php_codesniffer": "2.*"
         },
-        "time": "2018-08-24T07:25:03+00:00",
+        "time": "2018-09-05T03:37:46+00:00",
         "type": "think-framework",
         "installation-source": "dist",
         "notification-url": "https://packagist.org/downloads/",