webman_admin/src/plugin/admin/app/controller/auth/AdminRuleController.php
2022-09-14 15:33:18 +08:00

477 lines
14 KiB
PHP

<?php
namespace plugin\admin\app\controller\auth;
use plugin\admin\app\controller\Base;
use plugin\admin\app\controller\Crud;
use plugin\admin\app\model\AdminRole;
use plugin\admin\app\model\AdminRule;
use plugin\admin\app\Util;
use support\Request;
class AdminRuleController extends Base
{
/**
* @var AdminRule
*/
protected $model = null;
/**
* 增删改查
*/
use Crud;
/**
* 构造函数
*/
public function __construct()
{
$this->model = new AdminRule;
}
/**
* 获取权限树
*
* @param Request $request
* @return \support\Response
*/
public function tree(Request $request)
{
$this->syncRules();
$items = $this->model->get();
return $this->formatTree($items);
}
/**
* 根据类同步规则到数据库
*
* @return void
*/
protected function syncRules()
{
$items = $this->model->where('name', 'like', '%\\\\%')->get()->keyBy('name');
$methods_in_db = [];
$methods_in_files = [];
foreach ($items as $item) {
$class = $item->name;
if (strpos($class, '@')) {
$methods_in_db[$class] = $class;
continue;
}
if (class_exists($class)) {
$reflection = new \ReflectionClass($class);
$properties = $reflection->getDefaultProperties();
$no_need_auth = array_merge($properties['noNeedLogin'] ?? [], $properties['noNeedAuth'] ?? []);
$class = $reflection->getName();
$pid = $item->id;
$methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method) {
$method_name = $method->getName();
if (strpos($method_name, '__') === 0 || in_array($method_name, $no_need_auth)) {
continue;
}
$name = "$class@$method_name";
$methods_in_files[$name] = $name;
$title = Util::getCommentFirstLine($method->getDocComment()) ?: $method_name;
$menu = $items[$name] ?? [];
if ($menu) {
if ($menu->title != $title) {
AdminRule::where('name', $name)->update(['title' => $title]);
}
continue;
}
$menu = new AdminRule;
$menu->pid = $pid;
$menu->name = $name;
$menu->path = '';
$menu->component = '';
$menu->title = $title;
$menu->is_menu = 0;
$menu->save();
}
}
}
// 从数据库中删除已经不存在的方法
$menu_names_to_del = array_diff($methods_in_db, $methods_in_files);
if ($menu_names_to_del) {
AdminRule::whereIn('name', $menu_names_to_del)->delete();
}
}
/**
* 查询
*
* @param Request $request
* @return \support\Response
*/
public function select(Request $request)
{
[$where, $format, $page_size, $field, $order] = $this->selectInput($request);
$where['is_menu'] = 1;
$model = $this->model;
foreach ($where as $column => $value) {
if (is_array($value)) {
if (in_array($value[0], ['>', '=', '<', '<>'])) {
$model = $model->where($column, $value[0], $value[1]);
} elseif ($value[0] == 'in') {
$model = $model->whereIn($column, $value[1]);
} else {
$model = $model->whereBetween($column, $value);
}
} else {
$model = $model->where($column, $value);
}
}
$model = $model->orderBy($field, $order);
if (in_array($format, ['select', 'tree', 'table_tree'])) {
$items = $model->get();
if ($format == 'select') {
return $this->formatSelect($items);
} elseif ($format == 'tree') {
return $this->formatTree($items);
}
return $this->formatTableTree($items);
}
$paginator = $model->paginate($page_size);
return $this->json(0, 'ok', [
'items' => $paginator->items(),
'total' => $paginator->total()
]);
}
/**
* 添加
* @param Request $request
* @return \support\Response
*/
public function insert(Request $request)
{
$data = $request->post('data');
$table = $this->model->getTable();
$allow_column = Util::db()->select("desc $table");
if (!$allow_column) {
return $this->json(2, '表不存在');
}
$name = $data['name'];
if ($this->model->where('name', $name)->first()) {
return $this->json(1, "菜单key $name 已经存在");
}
$columns = array_column($allow_column, 'Field', 'Field');
foreach ($data as $col => $item) {
if (is_array($item)) {
$data[$col] = implode(',', $item);
}
}
$datetime = date('Y-m-d H:i:s');
if (isset($columns['created_at']) && !isset($data['created_at'])) {
$data['created_at'] = $datetime;
}
if (isset($columns['updated_at']) && !isset($data['updated_at'])) {
$data['updated_at'] = $datetime;
}
if (!empty($data['frame_src'])) {
$data['component'] = '';
}
$id = $this->model->insertGetId($data);
return $this->json(0, $id);
}
/**
* 删除
* @param Request $request
* @return \support\Response
* @throws \Support\Exception\BusinessException
*/
public function delete(Request $request)
{
$column = $request->post('column');
$value = $request->post('value');
$item = $this->model->where($column, $value)->first();
if (!$item) {
return $this->json(1, '记录不存在');
}
// 子规则一起删除
$delete_ids = $children_ids = [$item['id']];
while($children_ids) {
$children_ids = $this->model->whereIn('pid', $children_ids)->pluck('id')->toArray();
$delete_ids = array_merge($delete_ids, $children_ids);
}
$this->model->whereIn('id', $delete_ids)->delete();
return $this->json(0);
}
/**
* 一键生成菜单
*
* @param Request $request
* @return \support\Response
* @throws \Support\Exception\BusinessException
*/
public function create(Request $request)
{
$table_name = $request->input('table');
Util::checkTableName($table_name);
$name = $request->post('name');
$pid = $request->post('pid', 0);
$icon = $request->post('icon', '');
$path = '';
$overwrite = $request->post('overwrite');
$pid = (int)$pid;
if ($pid) {
$parent_menu = AdminRule::find($pid);
if (!$parent_menu) {
return $this->json(1, '父菜单不存在');
}
$path = $parent_menu['path'];
}
$table_basename = strpos($table_name, 'wa_') === 0 ? substr($table_name, 3) : $table_name;
$model_class = Util::camel($table_basename);
$suffix = substr($model_class, -2);
if ($suffix != 'ss' && $suffix != 'es') {
$model_class = rtrim($model_class, 's');
}
$controller_class = $model_class . config('plugin.admin.app.controller_suffix');
$path = trim($path, '/');
$path_backslash = str_replace('/', '\\', $path);
if ($path_backslash) {
$controller_namespace = "plugin\\admin\\app\\controller\\$path_backslash";
} else {
$controller_namespace = "plugin\\admin\\app\\controller";
}
$controller_file = base_path() . '/' . str_replace('\\', '/', $controller_namespace) . "/$controller_class.php";
$model_file = base_path() . "/plugin/admin/app/model/$model_class.php";
if (!$overwrite) {
if (is_file($controller_file)) {
return $this->json(1, substr($controller_file, strlen(base_path())) . '已经存在');
}
if (is_file($model_file)) {
return $this->json(1, substr($model_file, strlen(base_path())) . '已经存在');
}
}
// 创建model
$this->createModel($model_class, "plugin\\admin\\app\\model", $model_file, $table_name);
// 创建controller
$this->createController($controller_class, $controller_namespace, $controller_file, $model_class, $name);
// 菜单相关参数
$menu_path = str_replace('_', '', $table_basename);
$suffix = substr($menu_path, -2);
if ($suffix != 'ss' && $suffix != 'es') {
$menu_path = rtrim($menu_path, 's');
}
$componet = '/database/table/View';
$reflection = new \ReflectionClass("$controller_namespace\\$controller_class");
$controller_class_with_nsp = $reflection->getName();
$menu = AdminRule::where('name', $controller_class_with_nsp)->first();
if (!$menu) {
$menu = new AdminRule;
}
$menu->pid = $pid;
$menu->name = $controller_class_with_nsp;
$menu->path = $pid ? $menu_path : "/$menu_path";
$menu->component = $componet;
$menu->title = $name;
$menu->icon = $icon;
$menu->save();
$roles = admin('roles');
$rules = AdminRole::whereIn('id', $roles)->pluck('rules');
$rule_ids = [];
foreach ($rules as $rule_string) {
if (!$rule_string) {
continue;
}
$rule_ids = array_merge($rule_ids, explode(',', $rule_string));
}
// 不是超级管理员,则需要给当前管理员这个菜单的权限
if (!in_array('*', $rule_ids) && $roles){
$role = AdminRole::find(current($roles));
if ($role) {
$role->rules .= ",{$menu->id}";
}
$role->save();
}
return $this->json(0);
}
/**
* 创建model
*
* @param $class
* @param $namespace
* @param $file
* @param $table
* @return void
*/
protected function createModel($class, $namespace, $file, $table)
{
$this->mkdir($file);
$table_val = "'$table'";
$pk = 'id';
$properties = '';
$timestamps = '';
$columns = [];
try {
$database = config('database.connections')['plugin.admin.mysql']['database'];
//plugin.admin.mysql
foreach (Util::db()->select("select COLUMN_NAME,DATA_TYPE,COLUMN_KEY,COLUMN_COMMENT from INFORMATION_SCHEMA.COLUMNS where table_name = '$table' and table_schema = '$database'") as $item) {
if ($item->COLUMN_KEY === 'PRI') {
$pk = $item->COLUMN_NAME;
$item->COLUMN_COMMENT .= "(主键)";
}
$type = $this->getType($item->DATA_TYPE);
$properties .= " * @property $type \${$item->COLUMN_NAME} {$item->COLUMN_COMMENT}\n";
$columns[$item->COLUMN_NAME] = $item->COLUMN_NAME;
}
} catch (\Throwable $e) {}
if (!isset($columns['created_at']) || !isset($columns['updated_at'])) {
$timestamps = <<<EOF
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public \$timestamps = false;
EOF;
}
$properties = rtrim($properties) ?: ' *';
$model_content = <<<EOF
<?php
namespace $namespace;
/**
$properties
*/
class $class extends Base
{
/**
* The table associated with the model.
*
* @var string
*/
protected \$table = $table_val;
/**
* The primary key associated with the table.
*
* @var string
*/
protected \$primaryKey = '$pk';
$timestamps
}
EOF;
file_put_contents($file, $model_content);
}
/**
* 创建控制器
*
* @param $controller_class
* @param $namespace
* @param $file
* @param $model_class
* @param $name
* @return void
*/
protected function createController($controller_class, $namespace, $file, $model_class, $name)
{
$this->mkdir($file);
$controller_content = <<<EOF
<?php
namespace $namespace;
use plugin\admin\app\controller\Base;
use plugin\admin\app\controller\Crud;
use plugin\\admin\\app\\model\\$model_class;
use support\Request;
/**
* $name
*/
class $controller_class extends Base
{
/**
* 开启增删改查
*/
use Crud;
/**
* @var $model_class
*/
protected \$model = null;
/**
* 构造函数
*
* @return void
*/
public function __construct()
{
\$this->model = new $model_class;
}
}
EOF;
file_put_contents($file, $controller_content);
}
protected function mkdir($file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
}
/**
* 字段类型到php类型映射
*
* @param string $type
* @return string
*/
protected function getType(string $type)
{
if (strpos($type, 'int') !== false) {
return 'integer';
}
switch ($type) {
case 'varchar':
case 'string':
case 'text':
case 'date':
case 'time':
case 'guid':
case 'datetimetz':
case 'datetime':
case 'decimal':
case 'enum':
return 'string';
case 'boolean':
return 'integer';
case 'float':
return 'float';
default:
return 'mixed';
}
}
}