building-sign/app/command/Generate.php

314 lines
11 KiB
PHP
Raw Normal View History

2023-01-09 08:41:41 +00:00
<?php
declare (strict_types=1);
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\facade\Db;
class Generate extends Command
{
protected string $controller;
protected string $name;
protected string $title;
protected string $namespace;//控制器命名空间
protected string $viewDir;//view目录
protected string $jsFullDir;//js完整路径目录
protected string $jsDir;//js相对路径目录
protected string $controllerFullPath;//控制器完整路径
protected string $className;//控制器类名
protected function configure()
{
// 指令配置
$this->setName('generate')
->setDescription('生成后台基础crud')
->addOption('title', 't', Option::VALUE_REQUIRED, '标题')
->addOption('name', null, Option::VALUE_REQUIRED, '权限标识')
->addOption('controller', null, Option::VALUE_REQUIRED, '控制器命名空间');
}
protected function setInfo(string $controller, string $name, string $title)
{
$this->name = $name;
$this->controller = $controller;
$this->title = $title;
$this->controllerFullPath = $this->getControllerPathName();
$this->viewDir = $this->getViewDirName();
$this->jsFullDir = $this->getJsFullDirName();
$this->jsDir = $this->getJsDirName();
$controllerPath = explode('/', trim($controller, '/'));
$this->className = $controllerPath[count($controllerPath) - 1];
$namespace = 'app\\controller\\'.implode('\\', array_slice($controllerPath, 0, count($controllerPath) - 1));
$this->namespace = $namespace;
}
protected function execute(Input $input, Output $output)
{
$title = $input->getOption('title') ? trim($input->getOption('title')) : '';
$name = $input->getOption('name') ? trim($input->getOption('name')) : '';
$controller = $input->getOption('controller') ? trim($input->getOption('controller')) : '';
$this->setInfo($controller, $name, $title);
try {
$output->writeln('开始创建');
$output->writeln('1.菜单表生成数据...');
$dbRes = $this->createDb([
'title' => $title, 'name' => $name, 'controller' => $controller
]);
$successList = [];
if ($dbRes) {
$output->info('菜单表数据生成成功!');
$successList[] = '菜单数据生成!';
} else {
$output->warning('菜单表数据生成失败');
}
$output->writeln('2.生成控制器...');
if (is_file($this->controllerFullPath)) {
$output->error('控制器: '.$controller.' 已存在!');
}
if (!is_dir(dirname($this->controllerFullPath))) {
mkdir(dirname($this->controllerFullPath), 0755, true);
}
// 生成控制器
file_put_contents($this->controllerFullPath, $this->buildController());
$output->info($this->controllerFullPath.' 控制器生成成功!');
$successList[] = '创建文件:'.$this->controllerFullPath;
$output->writeln('3.生成视图文件...');
if (!is_dir($this->viewDir)) {
mkdir($this->viewDir, 0755, true);
}
foreach (['index', 'add', 'edit'] as $action) {
$actionHtml = sprintf('%s/%s.html', $this->viewDir, $action);
if (is_file($actionHtml)) {
$output->error($actionHtml.' 视图文件已存在!');
}
file_put_contents($actionHtml, $this->buildView($action));
$output->info($actionHtml.' 文件创建成功');
$successList[] = '创建文件:'.$actionHtml;
}
$output->info('视图文件生成成功!');
$jsPath = sprintf('%s/%s.js', $this->jsFullDir, unCamelize($this->className, '_'));
$output->writeln('4.生成js文件...');
if (!is_dir($this->jsFullDir)) {
mkdir($this->jsFullDir, 0755, true);
}
file_put_contents($jsPath, $this->buildJs());
$output->info($jsPath.' js文件创建成功');
$successList[] = '创建文件:'.$jsPath;
$output->newLine();
$output->writeln('信息汇总');
// 汇总信息
foreach ($successList as $success) {
$output->info($success);
}
$output->newLine();
$output->info(sprintf('此时可访问路径查看是否创建成功 /%s/index', unCamelize($controller)));
$output->newLine();
$output->warning('请注意,控制器中 $noNeedRight 默认开启了所有权限,如需纳入权限控制,请删除并在角色中选择对应权限');
// 指令输出
$output->info('创建完成');
} catch (\Exception $e) {
$output->error($e->getMessage());
}
}
/**
* 构建控制器内容
*
* @return array|false|string|string[]
*/
protected function buildController()
{
$controllerStubPath = __DIR__.DIRECTORY_SEPARATOR.'stubs/controller.stub';
$stub = file_get_contents($controllerStubPath);
return str_replace(['{%className%}', '{%namespace%}'], [
$this->className,
$this->namespace,
], $stub);
}
/**
* 构建视图文件内容
*
* @param string $action
* @return array|false|string|string[]
*/
protected function buildView(string $action)
{
$actionStubPath = __DIR__.DIRECTORY_SEPARATOR.'stubs/'.$action.'.stub';
$stub = file_get_contents($actionStubPath);
return str_replace(['{%path%}', '{%jsPath%}'], [
'/'.unCamelize($this->controller),
$this->jsDir.'/'.unCamelize($this->className, '_').'.js',
], $stub);
}
/**
* 构建js文件内容
*
* @return false|string
*/
protected function buildJs()
{
$actionStubPath = __DIR__.DIRECTORY_SEPARATOR.'stubs/js.stub';
return file_get_contents($actionStubPath);
}
/**
* 获取控制器完整路径
*
* @return string
*/
protected function getControllerPathName(): string
{
return $this->app->getBasePath().'controller/'.ltrim(str_replace('\\', '/', $this->controller), '/').'.php';
}
/**
* 获取对应view完整目录
*
* @return string
*/
protected function getViewDirName(): string
{
return $this->app->getRootPath().'view/'.ltrim(unCamelize($this->controller, '_'), '/');
}
/**
* 获取对应js完整目录
*
* @return string
*/
protected function getJsFullDirName(): string
{
$dir = $this->app->getRootPath().'public/static/'.ltrim(unCamelize($this->controller, '_'), '/');
return str_replace('/manager/', '/manager/js/', $dir);
}
/**
* 获取对应js相对目录
*
* @return string
*/
protected function getJsDirName(): string
{
return explode('/manager/', $this->jsFullDir)[1] ?? '';
}
/**
* 自动添加菜单表数据
*
* @param array $data
* @return bool
* @throws \Exception
*/
public function createDb(array $data): bool
{
$menuTable = 'menu';
$now = date('Y-m-d H:i:s');
if (!isset($data['title']) || !isset($data['name']) || !isset($data['controller'])) {
throw new \Exception('参数错误 请添加:--title 标题 --name 权限标识如aaa/bbb --controller 控制器 如manager/aaa/Bbb');
}
if (empty($data['title']) || empty($data['name']) || empty($data['controller'])) {
throw new \Exception('参数错误 请添加:--title 标题 --name 权限标识如aaa/bbb --controller 控制器 如manager/aaa/Bbb');
}
// 检查权限标识是否已存在
$already = Db::name('menu')->where('name', $data['name'])->whereOr('title', $data['title'])->count();
if ($already) {
throw new \Exception('菜单名称或标识已存在');
}
$href = unCamelize($data['controller']);
$insertMaster = [
'pid' => 0,
'title' => $data['title'], //名称
'icon' => $data['icon'] ?? 'fa-align-justify', //菜单图标
'name' => $data['name'], //权限标识
'href' => $href.'/index',//链接
'type' => 'menu',
'is_show' => 1,
'status' => 1,
'remark' => 'command generate',
'created_at' => $now,
];
$masterId = Db::name($menuTable)->insertGetId($insertMaster);
$masterPath = sprintf(',0,%d,', $masterId);
Db::name($menuTable)->where('id', $masterId)->update([
'path' => $masterPath
]);
$insertName = trim($data['name'], '/');
$insertHref = '/'.trim($href, '/');
$actionArr = $this->actionList();
// 基于权限标识生成下级列表 默认index add del edit modify
$insertAll = [];
foreach (array_keys($actionArr) as $action) {
$insertAll[] = [
'pid' => $masterId,
'title' => $actionArr[$action]['title'], //名称
'icon' => '', //菜单图标
'name' => $insertName.':'.$action, //权限标识
'href' => $insertHref.'/'.$action,//链接
'type' => 'action',
'is_show' => 1,
'status' => 1,
'remark' => 'command generate',
'path' => $masterPath,//此时的path为负极path
'created_at' => $now,
];
}
// 插入自己菜单
Db::name($menuTable)->insertAll($insertAll);
// 批量更新自己菜单path
Db::execute("update bee_$menuTable set `path`=concat(`path`, `id`, ',') where pid=$masterId");
return true;
}
protected function actionList(): array
{
return [
'index' => ['title' => '查看'],
'add' => ['title' => '添加'],
'edit' => ['title' => '编辑'],
'del' => ['title' => '删除'],
'modify' => ['title' => '属性设置'],
'sort' => ['title' => '排序'],
];
}
}