From eccf03e43fe07657efc4ba6d01f963346561fc5a Mon Sep 17 00:00:00 2001
From: Karson <karsonzhang@163.com>
Date: Fri, 15 Mar 2019 23:50:11 +0800
Subject: [PATCH] 新增一键CRUD类名冲突检测 新增一键CRUD自动传递请求参数 新增一键菜单之支持ThinkPHP5标准命名规则 新增Table.api.formatter.toggle自定义URL 新增Table.api.formatter.search自定义搜索字段 修复关联模型不同命名空间之间的BUG 优化时间字段修改器的判断

---
 application/admin/command/Crud.php                                   | 44 +++++++++++++++++++++++++++++---------------
 application/admin/command/Crud/stubs/javascript.stub                 |  2 +-
 application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub |  2 +-
 application/admin/command/Crud/stubs/mixins/radio.stub               |  2 +-
 application/admin/command/Crud/stubs/mixins/select.stub              |  2 +-
 application/admin/command/Menu.php                                   | 41 +++++++++++++++++++++++++++++++++--------
 public/assets/js/require-table.js                                    | 10 ++++++++--
 7 files changed, 74 insertions(+), 29 deletions(-)

diff --git a/application/admin/command/Crud.php b/application/admin/command/Crud.php
index eb4c89d..8850631 100755
--- a/application/admin/command/Crud.php
+++ b/application/admin/command/Crud.php
@@ -10,6 +10,7 @@ use think\console\input\Option;
 use think\console\Output;
 use think\Db;
 use think\Exception;
+use think\exception\ErrorException;
 use think\Lang;
 use think\Loader;
 
@@ -17,6 +18,9 @@ class Crud extends Command
 {
     protected $stubList = [];
 
+    protected $internalKeywords = [
+        'abstract', 'and', 'array', 'as', 'break', 'callable', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', 'extends', 'final', 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'include_once', 'instanceof', 'insteadof', 'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'require_once', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', 'while', 'xor'
+    ];
     /**
      * Selectpage搜索字段关联
      */
@@ -181,6 +185,7 @@ class Crud extends Command
         $controller = $input->getOption('controller');
         //自定义模型
         $model = $input->getOption('model');
+        $model = $model ? $model : $controller;
         //验证器类
         $validate = $model;
         //自定义显示字段
@@ -324,6 +329,8 @@ class Crud extends Command
                 $relations[] = [
                     //关联表基础名
                     'relationName'          => $relationName,
+                    //关联表类命名空间
+                    'relationNamespace'     => $relationNamespace,
                     //关联模型名
                     'relationModel'         => $relationModel,
                     //关联文件
@@ -369,6 +376,8 @@ class Crud extends Command
 
         //视图文件
         $viewArr = $controllerArr;
+        $lastValue = array_pop($viewArr);
+        $viewArr[] = Loader::parseName($lastValue, 0);
         array_unshift($viewArr, 'view');
         $viewDir = $adminPath . strtolower(implode(DS, $viewArr)) . DS;
 
@@ -383,7 +392,7 @@ class Crud extends Command
         //是否为删除模式
         $delete = $input->getOption('delete');
         if ($delete) {
-            $readyFiles = [$controllerFile, $modelFile, $validateFile, $addFile, $editFile, $indexFile, $langFile, $javascriptFile];
+            $readyFiles = [$controllerFile, $modelFile, $validateFile, $addFile, $editFile, $indexFile, $recyclebinFile, $langFile, $javascriptFile];
             foreach ($readyFiles as $k => $v) {
                 $output->warning($v);
             }
@@ -409,6 +418,7 @@ class Crud extends Command
                     case $addFile:
                     case $editFile:
                     case $indexFile:
+                    case $recyclebinFile:
                         $this->removeEmptyBaseDir($v, $viewArr);
                         break;
                     default:
@@ -522,6 +532,7 @@ class Crud extends Command
             }
             $relation['relationForeignKey'] = $relationForeignKey;
             $relation['relationPrimaryKey'] = $relationPrimaryKey;
+            $relation['relationClassName'] = $modelNamespace != $relation['relationNamespace'] ? $relation['relationNamespace'] . '\\' . $relation['relationName'] : $relation['relationName'];
         }
         unset($relation);
 
@@ -629,9 +640,8 @@ class Crud extends Command
                         $defaultDateTime = "{:date('{$phpFormat}')}";
                         $attrArr['data-date-format'] = $format;
                         $attrArr['data-use-current'] = "true";
-                        $fieldFunc = $fieldFunc ? "|{$fieldFunc}" : "";
                         $formAddElement = Form::text($fieldName, $defaultDateTime, $attrArr);
-                        $formEditElement = Form::text($fieldName, "{\$row.{$field}{$fieldFunc}}", $attrArr);
+                        $formEditElement = Form::text($fieldName, ($fieldFunc ? "{:\$row.{$field}?{$fieldFunc}(\$row.{$field}):''}" : "{\$row.{$field}{$fieldFunc}}"), $attrArr);
                     } elseif ($inputType == 'checkbox' || $inputType == 'radio') {
                         unset($attrArr['data-rule']);
                         $fieldName = $inputType == 'checkbox' ? $fieldName .= "[]" : $fieldName;
@@ -928,7 +938,7 @@ class Crud extends Command
             if ($langList) {
                 $this->writeToFile('lang', $data, $langFile);
             }
-        } catch (think\exception\ErrorException $e) {
+        } catch (ErrorException $e) {
             throw new Exception("Code: " . $e->getCode() . "\nLine: " . $e->getLine() . "\nMessage: " . $e->getMessage() . "\nFile: " . $e->getFile());
         }
 
@@ -956,7 +966,7 @@ class Crud extends Command
     public function {$methodName}()
     {
         return [{$itemString}];
-    }     
+    }
 EOD;
         $controllerAssignList[] = <<<EOD
         \$this->view->assign("{$fieldList}", \$this->model->{$methodName}());
@@ -980,7 +990,7 @@ EOD;
         $attrField = ucfirst($this->getCamelizeName($field));
         if ($inputType == 'datetime') {
             $return = <<<EOD
-return \$value && !is_numeric(\$value) ? strtotime(\$value) : \$value;
+return \$value === '' ? null : (\$value && !is_numeric(\$value) ? strtotime(\$value) : \$value);
 EOD;
         } elseif (in_array($inputType, ['checkbox', 'select'])) {
             $return = <<<EOD
@@ -1069,9 +1079,9 @@ EOD;
     /**
      * 获取已解析相关信息
      * @param string $module 模块名称
-     * @param string $name   自定义名称
-     * @param string $table  数据表名
-     * @param string $type   解析类型,本例中为controller、model、validate
+     * @param string $name 自定义名称
+     * @param string $table 数据表名
+     * @param string $type 解析类型,本例中为controller、model、validate
      * @return array
      */
     protected function getParseNameData($module, $name, $table, $type)
@@ -1087,6 +1097,10 @@ EOD;
             $parseArr = $arr;
             array_push($parseArr, $parseName);
         }
+        //类名不能为内部关键字
+        if (in_array(strtolower($parseName), $this->internalKeywords)) {
+            throw new Exception('Unable to use internal variable:' . $parseName);
+        }
         $appNamespace = Config::get('app_namespace');
         $parseNamespace = "{$appNamespace}\\{$module}\\{$type}" . ($arr ? "\\" . implode("\\", $arr) : "");
         $moduleDir = APP_PATH . $module . DS;
@@ -1097,7 +1111,7 @@ EOD;
     /**
      * 写入到文件
      * @param string $name
-     * @param array  $data
+     * @param array $data
      * @param string $pathname
      * @return mixed
      */
@@ -1118,7 +1132,7 @@ EOD;
     /**
      * 获取替换后的数据
      * @param string $name
-     * @param array  $data
+     * @param array $data
      * @return string
      */
     protected function getReplacedStub($name, $data)
@@ -1183,7 +1197,7 @@ EOD;
 
     /**
      * 读取数据和语言数组列表
-     * @param array   $arr
+     * @param array $arr
      * @param boolean $withTpl
      * @return array
      */
@@ -1303,8 +1317,8 @@ EOD;
 
     /**
      * 判断是否符合指定后缀
-     * @param string $field     字段名称
-     * @param mixed  $suffixArr 后缀
+     * @param string $field 字段名称
+     * @param mixed $suffixArr 后缀
      * @return boolean
      */
     protected function isMatchSuffix($field, $suffixArr)
@@ -1371,7 +1385,7 @@ EOD;
      * @param string $field
      * @param string $datatype
      * @param string $extend
-     * @param array  $itemArr
+     * @param array $itemArr
      * @return string
      */
     protected function getJsColumn($field, $datatype = '', $extend = '', $itemArr = [])
diff --git a/application/admin/command/Crud/stubs/javascript.stub b/application/admin/command/Crud/stubs/javascript.stub
index 12fbb70..933cfa3 100644
--- a/application/admin/command/Crud/stubs/javascript.stub
+++ b/application/admin/command/Crud/stubs/javascript.stub
@@ -5,7 +5,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             // 初始化表格参数配置
             Table.api.init({
                 extend: {
-                    index_url: '{%controllerUrl%}/index',
+                    index_url: '{%controllerUrl%}/index' + location.search,
                     add_url: '{%controllerUrl%}/add',
                     edit_url: '{%controllerUrl%}/edit',
                     del_url: '{%controllerUrl%}/del',
diff --git a/application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub b/application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub
index 712daeb..3da6462 100755
--- a/application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub
+++ b/application/admin/command/Crud/stubs/mixins/modelrelationmethod.stub
@@ -1,5 +1,5 @@
 
     public function {%relationMethod%}()
     {
-        return $this->{%relationMode%}('{%relationName%}', '{%relationForeignKey%}', '{%relationPrimaryKey%}', [], 'LEFT')->setEagerlyType(0);
+        return $this->{%relationMode%}('{%relationClassName%}', '{%relationForeignKey%}', '{%relationPrimaryKey%}', [], 'LEFT')->setEagerlyType(0);
     }
\ No newline at end of file
diff --git a/application/admin/command/Crud/stubs/mixins/radio.stub b/application/admin/command/Crud/stubs/mixins/radio.stub
index 527151a..71234a6 100644
--- a/application/admin/command/Crud/stubs/mixins/radio.stub
+++ b/application/admin/command/Crud/stubs/mixins/radio.stub
@@ -1,6 +1,6 @@
 
     public function {%methodName%}($value, $data)
-    {        
+    {
         $value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : '');
         $list = $this->{%listMethodName%}();
         return isset($list[$value]) ? $list[$value] : '';
diff --git a/application/admin/command/Crud/stubs/mixins/select.stub b/application/admin/command/Crud/stubs/mixins/select.stub
index 527151a..71234a6 100644
--- a/application/admin/command/Crud/stubs/mixins/select.stub
+++ b/application/admin/command/Crud/stubs/mixins/select.stub
@@ -1,6 +1,6 @@
 
     public function {%methodName%}($value, $data)
-    {        
+    {
         $value = $value ? $value : (isset($data['{%field%}']) ? $data['{%field%}'] : '');
         $list = $this->{%listMethodName%}();
         return isset($list[$value]) ? $list[$value] : '';
diff --git a/application/admin/command/Menu.php b/application/admin/command/Menu.php
index affe024..02ec31f 100755
--- a/application/admin/command/Menu.php
+++ b/application/admin/command/Menu.php
@@ -12,6 +12,7 @@ use think\console\Input;
 use think\console\input\Option;
 use think\console\Output;
 use think\Exception;
+use think\Loader;
 
 class Menu extends Command
 {
@@ -52,6 +53,18 @@ class Menu extends Command
             $ids = [];
             $list = $this->model->where(function ($query) use ($controller, $equal) {
                 foreach ($controller as $index => $item) {
+                    if (stripos($item, '_') !== false) {
+                        $item = Loader::parseName($item, 1);
+                    }
+                    if (stripos($item, '/') !== false) {
+                        $controllerArr = explode('/', $item);
+                        end($controllerArr);
+                        $key = key($controllerArr);
+                        $controllerArr[$key] = Loader::parseName($controllerArr[$key]);
+                    } else {
+                        $controllerArr = [Loader::parseName($item)];
+                    }
+                    $item = str_replace('_', '\_', implode('/', $controllerArr));
                     if ($equal) {
                         $query->whereOr('name', 'eq', $item);
                     } else {
@@ -82,10 +95,17 @@ class Menu extends Command
 
         if (!in_array('all-controller', $controller)) {
             foreach ($controller as $index => $item) {
-                $controllerArr = explode('/', $item);
-                end($controllerArr);
-                $key = key($controllerArr);
-                $controllerArr[$key] = ucfirst($controllerArr[$key]);
+                if (stripos($item, '_') !== false) {
+                    $item = Loader::parseName($item, 1);
+                }
+                if (stripos($item, '/') !== false) {
+                    $controllerArr = explode('/', $item);
+                    end($controllerArr);
+                    $key = key($controllerArr);
+                    $controllerArr[$key] = ucfirst($controllerArr[$key]);
+                } else {
+                    $controllerArr = [ucfirst($item)];
+                }
                 $adminPath = dirname(__DIR__) . DS . 'controller' . DS . implode(DS, $controllerArr) . '.php';
                 if (!is_file($adminPath)) {
                     $output->error("controller not found");
@@ -159,10 +179,15 @@ class Menu extends Command
     protected function importRule($controller)
     {
         $controller = str_replace('\\', '/', $controller);
-        $controllerArr = explode('/', $controller);
-        end($controllerArr);
-        $key = key($controllerArr);
-        $controllerArr[$key] = ucfirst($controllerArr[$key]);
+        if (stripos($controller, '/') !== false) {
+            $controllerArr = explode('/', $controller);
+            end($controllerArr);
+            $key = key($controllerArr);
+            $controllerArr[$key] = ucfirst($controllerArr[$key]);
+        } else {
+            $key = 0;
+            $controllerArr = [ucfirst($controller)];
+        }
         $classSuffix = Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : '';
         $className = "\\app\\admin\\controller\\" . implode("\\", $controllerArr) . $classSuffix;
 
diff --git a/public/assets/js/require-table.js b/public/assets/js/require-table.js
index 6b28bf3..151535b 100644
--- a/public/assets/js/require-table.js
+++ b/public/assets/js/require-table.js
@@ -479,14 +479,20 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
                     var color = typeof this.color !== 'undefined' ? this.color : 'success';
                     var yes = typeof this.yes !== 'undefined' ? this.yes : 1;
                     var no = typeof this.no !== 'undefined' ? this.no : 0;
+                    var url = typeof this.url !== 'undefined' ? this.url : '';
                     return "<a href='javascript:;' data-toggle='tooltip' title='" + __('Click to toggle') + "' class='btn-change' data-id='"
-                        + row.id + "' data-params='" + this.field + "=" + (value == yes ? no : yes) + "'><i class='fa fa-toggle-on " + (value == yes ? 'text-' + color : 'fa-flip-horizontal text-gray') + " fa-2x'></i></a>";
+                        + row.id + "' " + (url ? "data-url='" + url + "'" : "") + " data-params='" + this.field + "=" + (value == yes ? no : yes) + "'><i class='fa fa-toggle-on " + (value == yes ? 'text-' + color : 'fa-flip-horizontal text-gray') + " fa-2x'></i></a>";
                 },
                 url: function (value, row, index) {
                     return '<div class="input-group input-group-sm" style="width:250px;margin:0 auto;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>';
                 },
                 search: function (value, row, index) {
-                    return '<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', value) + '" data-field="' + this.field + '" data-value="' + value + '">' + value + '</a>';
+                    var field = this.field;
+                    if (typeof this.customField !== 'undefined' && typeof row[this.customField] !== 'undefined') {
+                        value = row[this.customField];
+                        field = this.customField;
+                    }
+                    return '<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', value) + '" data-field="' + field + '" data-value="' + value + '">' + value + '</a>';
                 },
                 addtabs: function (value, row, index) {
                     var url = Table.api.replaceurl(this.url, row, this.table);
--
libgit2 0.24.0