diff --git a/extend/catcher/generate/Generator.php b/extend/catcher/generate/Generator.php index 4dde917..425ab94 100644 --- a/extend/catcher/generate/Generator.php +++ b/extend/catcher/generate/Generator.php @@ -8,10 +8,14 @@ use catcher\generate\factory\Migration; use catcher\generate\factory\Model; use catcher\generate\factory\Route; use catcher\generate\factory\SQL; +use catcher\library\Composer; use think\facade\Db; class Generator { + + const NEED_PACKAGE = 'nikic/php-parser'; + /** * generate * @@ -21,6 +25,13 @@ class Generator */ public function done($params) { + // 判断是否安装了扩展包 + if (!(new Composer)->hasPackage(self::NEED_PACKAGE)) { + throw new FailedException( + sprintf('you must use [ composer require --dev %s]', self::NEED_PACKAGE) + ); + } + $params = \json_decode($params['data'], true); [$controller, $model] = $this->parseParams($params); @@ -86,7 +97,7 @@ class Generator switch ($type) { case 'controller': - return (new Controller())->getContent($controller); + return (new Controller())->dones(); case 'model': return (new Model())->getContent($model); default: diff --git a/extend/catcher/generate/build/CatchBuild.php b/extend/catcher/generate/build/CatchBuild.php index 480978c..817b6dc 100644 --- a/extend/catcher/generate/build/CatchBuild.php +++ b/extend/catcher/generate/build/CatchBuild.php @@ -1,26 +1,46 @@ astBuilder = app(BuilderFactory::class); } + /** + * 命名空间 + * + * @time 2020年11月19日 + * @param string $namespace + * @return $this + */ public function namespace(string $namespace) { - $this->astBuilder = $this->astBuilder->namespace('god'); + $this->astBuilder = $this->astBuilder->namespace($namespace); return $this; } + /** + * use 方法体 + * + * @time 2020年11月19日 + * @param $use + * @return $this + */ public function use($use) { $this->astBuilder->addStmt($use); @@ -29,21 +49,93 @@ class PHPBuild } + /** + * class 模版 + * + * @time 2020年11月19日 + * @param Classes $class + * @param \Closure $function + * @return $this + */ public function class(Classes $class, \Closure $function) { $function($class); $this->astBuilder->addStmt($class->build()); + return $this; + } + + /** + * 条件 + * + * @time 2020年11月19日 + * @param $condition + * @param \Closure $closure + * @return $this + */ + public function when($condition, \Closure $closure) + { + if ($condition && $closure instanceof \Closure) { + $closure($this); + } + + return $this; + } + + /** + * 获取内容 + * + * @time 2020年11月19日 + * @return string + */ + public function getContent() + { + $stmts = array($this->astBuilder->getNode()); + + $prettyPrinter = new Standard(); + + return $prettyPrinter->prettyPrintFile($stmts); + } + + /** + * 输出 + * + * @time 2020年11月19日 + * @return string + */ + public function output() + { + return FileSystem::put($this->outPath . $this->filename, $this->getContent()); + } + + /** + * 输出 Path + * + * @time 2020年11月19日 + * @param $path + * @return $this + */ + public function path($path) + { + CatchAdmin::makeDirectory($path); + + $this->outPath = $path; return $this; } - - public function finish() + /** + * 设置文件名 + * + * @time 2020年11月19日 + * @param $name + * @return mixed + */ + public function filename($name) { - $stmts = array($this->astBuilder->getNode()); - $prettyPrinter = new Standard(); - dd($prettyPrinter->prettyPrintFile($stmts)); + $this->filename = $name; + + return $this; } } \ No newline at end of file diff --git a/extend/catcher/generate/build/classes/Classes.php b/extend/catcher/generate/build/classes/Classes.php index ac9be3c..75c6388 100644 --- a/extend/catcher/generate/build/classes/Classes.php +++ b/extend/catcher/generate/build/classes/Classes.php @@ -1,17 +1,27 @@ classBuild = (new BuilderFactory())->class($name); + } + /** + * 设置 comment * - * @time 2020年11月17日 - * @param $name + * @time 2020年11月19日 + * @param string $comment * @return $this */ - public function name($name) + public function docComment($comment="\r\n") { - $this->data['name'] = $name; + $this->classBuild->setDocComment($comment); return $this; } @@ -23,7 +33,7 @@ class Classes extends Iteration */ public function extend($extend) { - $this->data['extend'] = $extend; + $this->classBuild->extend($extend); return $this; } @@ -33,9 +43,9 @@ class Classes extends Iteration * @param $interfaces * @return $this */ - public function interfaces($interfaces) + public function implement($interfaces) { - $this->data['interfaces'] = $interfaces; + $this->classBuild->implement($interfaces); return $this; } @@ -44,9 +54,9 @@ class Classes extends Iteration * @time 2020年11月17日 * @return $this */ - public function isAbstract() + public function abstract() { - $this->data['type'] = 'Abstract'; + $this->classBuild->makeAbstract(); return $this; } @@ -55,21 +65,36 @@ class Classes extends Iteration * @time 2020年11月17日 * @return $this */ - public function isFinal() + public function final() { - $this->data['type'] = 'Final'; + $this->classBuild->makeFinal(); return $this; } - /** - * @time 2020年11月17日 - * @param $type - * @param $param - * @return void - */ - public function construct($type, $param) + public function build() { - $this->data['construct'][] = [$type, $param]; + return $this->classBuild; + } + + public function addMethod(Methods $method) + { + $this->classBuild->addStmt($method->build()); + + return $this; + } + + public function addProperty(Property $property) + { + $this->classBuild->addStmt($property->build()); + + return $this; + } + + public function addTrait(Traits $trait) + { + $this->classBuild->addStmt($trait->build()); + + return $this; } } diff --git a/extend/catcher/generate/build/classes/Methods.php b/extend/catcher/generate/build/classes/Methods.php index 304cd8b..0a23cfa 100644 --- a/extend/catcher/generate/build/classes/Methods.php +++ b/extend/catcher/generate/build/classes/Methods.php @@ -1,55 +1,43 @@ method['name'] = $method; + $this->methodBuild = (new BuilderFactory())->method($name); + } + + public function public() + { + $this->methodBuild->makePublic(); return $this; } - /** - * set visible - * - * @time 2020年11月16日 - * @param string $visibility - * @return $this - */ - public function visible(string $visibility) + public function protected() { - $this->method['visible'] = $visibility; + $this->methodBuild->makeProtected(); return $this; } - public function makePublic() + public function private() { - $this->method['visible'] = 'public'; - - return $this; - } - - public function makeProtected() - { - $this->method['visible'] = 'protected'; - - return $this; - } - - public function makePrivate() - { - $this->method['visible'] = 'private'; + $this->methodBuild->makePrivate(); return $this; } @@ -65,25 +53,45 @@ class Methods extends Iteration */ public function param($param, $type = null, $default = null) { - $this->method['params'][] = [ - 'type' => $type, - 'param' => $param, - 'default' => $default, - ]; + $param = (new BuilderFactory())->param($param); + + if ($type) { + $param = $param->setType($type); + } + + if ($default) { + $param = $param->setDefault($default); + } + + $this->methodBuild->addParam( + $param + ); return $this; } /** - * 返回内容 + * 定义 * - * @time 2020年11月17日 - * @param $return + * @time 2020年11月18日 + * @param $variable + * @param $value * @return $this */ - public function return($return) + public function declare($variable, $value) { - $this->method['return'] = $return; + $smt = new Expression( + new Assign( + new PropertyFetch( + new Variable('this'), + new Identifier($variable) + ), + new Variable($value) + ) + ); + + $this->methodBuild->addStmt($smt); + return $this; } @@ -91,12 +99,12 @@ class Methods extends Iteration * 返回值 * * @time 2020年11月16日 - * @param $return + * @param $returnType * @return $this */ - public function returnType($return) + public function returnType($returnType) { - $this->method['return'] = $return; + $this->methodBuild->setReturnType($returnType); return $this; } @@ -109,9 +117,9 @@ class Methods extends Iteration * @param $comment * @return $this */ - public function docComment($comment) + public function docComment(string $comment) { - $this->method['comment'] = $comment; + $this->methodBuild->setDocComment($comment); return $this; } @@ -124,7 +132,7 @@ class Methods extends Iteration */ public function toAbstract() { - $this->method['type'] = 'Abstract'; + $this->methodBuild->makeAbstract(); return $this; } @@ -137,23 +145,14 @@ class Methods extends Iteration */ public function toFinal() { - $this->method['type'] = 'Final'; + $this->methodBuild->makeFinal(); return $this; } - /** - * join - * - * @time 2020年11月17日 - * @return $this - */ - public function join() + + public function build() { - $this->data[] = $this->method; - - $this->method = []; - - return $this; + return $this->methodBuild; } } diff --git a/extend/catcher/generate/build/classes/Property.php b/extend/catcher/generate/build/classes/Property.php index 6ae940d..60cabfe 100644 --- a/extend/catcher/generate/build/classes/Property.php +++ b/extend/catcher/generate/build/classes/Property.php @@ -3,7 +3,7 @@ namespace catcher\generate\build\classes; use PhpParser\BuilderFactory; -class Properties +class Property { protected $propertyBuild; @@ -89,7 +89,7 @@ class Properties return $this; } - + public function build() { return $this->propertyBuild; diff --git a/extend/catcher/generate/build/classes/Traits.php b/extend/catcher/generate/build/classes/Traits.php index 8a4f651..c98a860 100644 --- a/extend/catcher/generate/build/classes/Traits.php +++ b/extend/catcher/generate/build/classes/Traits.php @@ -1,37 +1,88 @@ trait)) { - $this->data[] = $this->trait; + $this->build = new BuilderFactory; - $this->trait = []; - - return $this; - } - - $this->trait['name'] = $name; + $this->traitBuild = call_user_func_array([$this->build, 'useTrait'], $names); return $this; } - public function adaptation($name) + public function and($name) { - $this->trait['adaptation'] = $name; + $this->traitBuild->and($name); + + return $this; } + /** + * with + * + * @time 2020年11月19日 + * @param \Closure|null $closure + * @return $this + */ + public function with(\Closure $closure = null) + { + if ($closure instanceof \Closure) { + $this->traitBuild->withe($closure($this)); + + return $this; + } + + return $this; + } + + /** + * @time 2020年11月19日 + * @param $name + * @param null $method + * @return $this + */ + public function adaptation($name, $method = null) + { + $this->build = $this->build->traitUseAdaptation($name. $method); + + return $this; + } + + /** + * @time 2020年11月19日 + * @param $name + * @return $this + */ + public function as($name) + { + $this->build->as($name); + + return $this; + } + + + /** + * @time 2020年11月19日 + * @param $name + * @return $this + */ public function insteadof($name) { - $this->trait['insteadof'] = $name; + $this->build->insteadof($name); + + return $this; } - public function as($as) + public function build() { - $this->trait['as'] = $as; + return $this->traitBuild; } } diff --git a/extend/catcher/generate/build/classes/Uses.php b/extend/catcher/generate/build/classes/Uses.php index d8ed389..66d51eb 100644 --- a/extend/catcher/generate/build/classes/Uses.php +++ b/extend/catcher/generate/build/classes/Uses.php @@ -1,23 +1,29 @@ use($name); - foreach ($uses as $key => $use) { - if (Str::contains($use, $delimiter)) { - $uses[$key] = explode($delimiter, $use); - } + if ($as) { + $build->as($as); } - $this->data = $uses; + return $build; + } + + public function function(string $function) + { + return (new BuilderFactory())->useFunction($function); + } + + public function const(string $const) + { + return (new BuilderFactory())->useConst($const); } } \ No newline at end of file diff --git a/extend/catcher/generate/build/traits/CatchMethodReturn.php b/extend/catcher/generate/build/traits/CatchMethodReturn.php index 36e7c0e..3e7c715 100644 --- a/extend/catcher/generate/build/traits/CatchMethodReturn.php +++ b/extend/catcher/generate/build/traits/CatchMethodReturn.php @@ -2,30 +2,129 @@ namespace catcher\generate\build\traits; -class MethodReturn +use PhpParser\Node\Arg; +use PhpParser\Node\Expr\MethodCall; +use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\Expr\StaticCall; +use PhpParser\Node\Expr\Variable; +use PhpParser\Node\Identifier; +use PhpParser\Node\Name; +use PhpParser\Node\Stmt\Return_; + +trait CatchMethodReturn { - public function index() + /** + * 列表 + * + * @time 2020年11月18日 + * @param $model + * @return $this + */ + public function index($model) { + $class = new Name('CatchResponse'); + $arg = new Arg(new MethodCall( + new PropertyFetch( + new Variable('this'), new Identifier($model) + ), + new Identifier('getList') + )); + + $this->methodBuild->addStmt(new Return_(new StaticCall($class, 'paginate', [$arg]))); + + return $this; } - public function save() + /** + * 保存 + * + * @time 2020年11月18日 + * @param $model + * @return $this + */ + public function save($model) { + $arg = new Arg(new MethodCall( + new PropertyFetch( + new Variable('this'), new Identifier($model) + ), + new Identifier('storeBy'), [new Arg(new MethodCall(new Variable('request'), new Identifier('post')))] + )); + $class = new Name('CatchResponse'); + + $this->methodBuild->addStmt(new Return_(new StaticCall($class, 'success', [$arg]))); + + return $this; } - public function update() + /** + * 更新 + * + * @time 2020年11月18日 + * @param $model + * @return $this + */ + public function update($model) { + $arg = new Arg(new MethodCall( + new PropertyFetch( + new Variable('this'), new Identifier($model) + ), + new Identifier('updateBy'), [ + new Arg(new Variable('id')), + new Arg(new MethodCall(new Variable('request'), new Identifier('post'))) + ] + )); + $class = new Name('CatchResponse'); + + $this->methodBuild->addStmt(new Return_(new StaticCall($class, 'success', [$arg]))); + + return $this; } - public function read() + public function read($model) { + $arg = new Arg(new MethodCall( + new PropertyFetch( + new Variable('this'), new Identifier($model) + ), + new Identifier('findBy'), [ + new Arg(new Variable('id')) + ] + )); + $class = new Name('CatchResponse'); + + $this->methodBuild->addStmt(new Return_(new StaticCall($class, 'success', [$arg]))); + + return $this; } - public function delete() + /** + * 删除 + * + * @time 2020年11月18日 + * @param $model + * @return $this + */ + public function delete($model) { + $arg = new Arg(new MethodCall( + new PropertyFetch( + new Variable('this'), new Identifier($model) + ), + new Identifier('deleteBy'), [ + new Arg(new Variable('id')) + ] + )); + $class = new Name('CatchResponse'); + + $this->methodBuild->addStmt(new Return_(new StaticCall($class, 'success', [$arg]))); + + return $this; } } \ No newline at end of file diff --git a/extend/catcher/generate/build/types/Arr.php b/extend/catcher/generate/build/types/Arr.php index ca22e96..8783a14 100644 --- a/extend/catcher/generate/build/types/Arr.php +++ b/extend/catcher/generate/build/types/Arr.php @@ -1,20 +1,28 @@ setDocComment( + new Doc('// ' . $field['comment']) + ); + } + $items[] = $arrItem; } - return new \PhpParser\Node\Expr\Array_($items); + return new Array_($items); } } diff --git a/extend/catcher/generate/factory/Controller.php b/extend/catcher/generate/factory/Controller.php index 84b6931..74149a7 100644 --- a/extend/catcher/generate/factory/Controller.php +++ b/extend/catcher/generate/factory/Controller.php @@ -1,14 +1,35 @@ getGeneratePath($params['controller']); - if (file_put_contents($controllerPath, $this->getContent($params))) { - return $controllerPath; + + if (FileSystem::put($controllerPath, $this->getContent($params))) { + return $controllerPath; } throw new FailedException($params['controller'] . ' generate failed~'); @@ -39,109 +61,136 @@ class Controller extends Factory throw new FailedException('params has lost~'); } - $template = new Template(); // parse controller [$className, $namespace] = $this->parseFilename($params['controller']); + + [$model, $modelNamespace] = $this->parseFilename($params['model']); + + $asModel = lcfirst(Str::contains($model, 'Model') ? : $model . 'Model'); + if (!$className) { throw new FailedException('未填写控制器名称'); } - - // parse model - [$model, $modelNamespace] = $this->parseFilename($params['model']); - $use = implode(';',[ - 'use ' . $params['model'] .' as '. $model . 'Model', - ]) . ';'; + $use = new Uses(); + $class = new Classes($className); - $content = $template->header() . - $template->nameSpace($namespace) . - str_replace('{USE}', $model ? $use : '', $template->uses()) . - $template->createClass($className); + return (new CatchBuild())->namespace($namespace) + ->use($use->name('catcher\base\CatchRequest', 'Request')) + ->use($use->name('catcher\CatchResponse')) + ->use($use->name('catcher\base\CatchController')) + ->use($use->name($modelNamespace . '\\' . ucfirst($model), $asModel)) + ->class($class->extend('CatchController')->docComment(), function (Classes $class) use ($asModel) { + foreach ($this->getMethods($asModel) as $method) { + $class->addMethod($method); + } - return str_replace('{CONTENT}', ($model ? $template->construct($model.'Model') : '') . rtrim($this->content($params, $template), "\r\n"), $content); + $class->addProperty( + (new Property($asModel))->public() + ); + + }) + ->getContent(); } + /** - * parse use + * 方法集合 * - * @time 2020年04月28日 - * @param $params - * @return string + * @time 2020年11月19日 + * @param $model + * @return array */ - protected function parseUse($params) + protected function getMethods($model) { + $date = date('Y年m月d日 H:i'); - } - /** - * content - * - * @time 2020年04月27日 - * @param $params - * @param $template - * @return string - */ - protected function content($params, $template) - { - $content = ''; - if ($params['restful']) { - $methods = $this->restful(); - $this->methods = array_merge($this->methods, $methods); - foreach ($methods as $method) { - $content .= $template->{$method[0]}(); - } - } - - /** - if (!empty($params['other_function'])) { - $others = $this->parseOtherMethods($params['other_function']); - $this->methods = array_merge($this->methods, $others); - foreach ($others as $other) { - $content .= $template->otherFunction($other[0], $other[1]); - } - }*/ - - return $content; - } - - /** - * parse $method - * class_method/http_method - * @time 2020年04月27日 - * @param $methods - * @return false|string[] - */ - public function parseOtherMethods($methods) - { - $_methods = []; - - foreach ($methods as $method) { - if (Str::contains($method, '/')) { - $_methods[] = explode('/', $method); - } else { - // 默认使用 Get 方式 - $_methods[] = [$method, 'get']; - } - } - - return $_methods; - } - - /** - * restful 路由 - * - * @time 2020年04月27日 - * @return \string[][] - */ - public function restful() - { return [ - ['index', 'get'], - ['save', 'post'], - ['read', 'get'], - ['update', 'put'], - ['delete', 'delete'], + (new Methods('__construct')) + ->public() + ->param($model, ucfirst($model)) + ->docComment("\r\n") + ->declare($model, $model), + + (new Methods('index'))->public() + ->param('request', 'Request') + ->docComment( + <<returnType('\think\Response')->index($model), + + (new Methods('save')) + ->public() + ->param('request', 'Request') + ->docComment( + <<returnType('\think\Response') + ->save($model), + + + (new Methods('read'))->public() + ->param('id') + ->docComment( + <<returnType('\think\Response')->read($model), + + + (new Methods('update'))->public() + ->param('request', 'Request') + ->param('id') + ->docComment( + <<returnType('\think\Response')->update($model), + + + (new Methods('delete'))->public() + ->param('id') + ->docComment( + <<returnType('\think\Response')->delete($model), + ]; } - } diff --git a/extend/catcher/generate/factory/Factory.php b/extend/catcher/generate/factory/Factory.php index f4b970b..987bf0c 100644 --- a/extend/catcher/generate/factory/Factory.php +++ b/extend/catcher/generate/factory/Factory.php @@ -42,7 +42,7 @@ abstract class Factory CatchAdmin::makeDirectory($filePath); - return $filePath . DIRECTORY_SEPARATOR . $filename . '.php'; + return $filePath . DIRECTORY_SEPARATOR . ucfirst($filename ). '.php'; } /** diff --git a/extend/catcher/generate/factory/Model.php b/extend/catcher/generate/factory/Model.php index 45109a7..64730a6 100644 --- a/extend/catcher/generate/factory/Model.php +++ b/extend/catcher/generate/factory/Model.php @@ -2,21 +2,34 @@ namespace catcher\generate\factory; use catcher\exceptions\FailedException; -use catcher\generate\template\Model as Template; -use catcher\Utils; -use Phinx\Util\Util; +use catcher\facade\FileSystem; +use catcher\generate\build\CatchBuild; +use catcher\generate\build\classes\Classes; +use catcher\generate\build\classes\Property; +use catcher\generate\build\classes\Traits; +use catcher\generate\build\classes\Uses; +use catcher\generate\build\types\Arr; +use catcher\traits\db\BaseOptionsTrait; +use catcher\traits\db\ScopeTrait; use think\facade\Db; use think\helper\Str; class Model extends Factory { + /** + * done + * + * @time 2020年11月19日 + * @param $params + * @return string + */ public function done($params) { $content = $this->getContent($params); $modelPath = $this->getGeneratePath($params['model']); - file_put_contents($modelPath, $content); + FileSystem::put($modelPath, $content); if (!file_exists($modelPath)) { throw new FailedException('create model failed'); @@ -34,9 +47,6 @@ class Model extends Factory */ public function getContent($params) { - // TODO: Implement done() method. - $template = new Template(); - $extra = $params['extra']; $table = $params['table']; @@ -53,43 +63,31 @@ class Model extends Factory throw new FailedException('model name not set'); } - $content = $template->useTrait($extra['soft_delete']) . - $template->name(str_replace(Utils::tablePrefix(), '', $table)) . - $template->field($this->parseField($table)); + $softDelete = $extra['soft_delete']; - $class = $template->header() . - $template->nameSpace($namespace) . - $template->uses($extra['soft_delete']) . - $template->createModel($modelName, $table); + return (new CatchBuild)->namespace($namespace) + ->use((new Uses())->name('catcher\base\CatchModel', 'Model')) + ->when(!$softDelete, function (CatchBuild $build){ + $build->use((new Uses())->name(BaseOptionsTrait::class)); + $build->use((new Uses())->name(ScopeTrait::class)); + }) + ->class((new Classes($modelName))->extend('Model')->docComment(), + function (Classes $class) use ($softDelete, $table) { + if (!$softDelete) { + $class->addTrait( + (new Traits())->use('BaseOptionsTrait', 'ScopeTrait') + ); + } - return str_replace('{CONTENT}', $content, $class); - } + $class->addProperty( + (new Property('name'))->default($table)->docComment('// 表名') + ); - /** - * parse field - * - * @time 2020年04月28日 - * @param $table - * @return string - */ - protected function parseField($table) - { - if (!$this->hasTableExists($table)) { - return false; - } - - $columns = Db::query('show full columns from ' . $table); - - $new = []; - foreach ($columns as $field) { - $new[$field['Field']] = $field['Comment']; - } - - $fields = []; - foreach ($new as $field => $comment) { - $fields[] = sprintf("'%s', // %s", $field, $comment); - } - - return implode("\r\n\t\t", $fields); + $class->addProperty( + (new Property('field'))->default( + (new Arr)->build(Db::getFields($table)) + )->docComment('// 数据库字段映射') + ); + })->getContent(); } } \ No newline at end of file diff --git a/extend/catcher/generate/factory/Route.php b/extend/catcher/generate/factory/Route.php index 415b63e..aed9a55 100644 --- a/extend/catcher/generate/factory/Route.php +++ b/extend/catcher/generate/factory/Route.php @@ -1,6 +1,7 @@ controllerName . '路由'; array_unshift($route, $comment); + if (file_exists($router)) { - return file_put_contents($router, $this->parseRoute($router, $route)); + return FileSystem::put($router, $this->parseRoute($router, $route)); } - return file_put_contents($router, $this->header() . $comment. implode(';'. PHP_EOL , $route) . ';'); + return FileSystem::put($router, $this->header() . $comment. implode(';'. PHP_EOL , $route) . ';'); } protected function parseRoute($path, $route)