样机小程序

This commit is contained in:
2025-12-08 17:37:34 +08:00
commit d19bb9046b
175 changed files with 19427 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
<?php
namespace app\common\utils;
use Firebase\JWT\JWT as FirebaseJWT;
use Firebase\JWT\Key;
use support\exception\BusinessException;
class Jwt
{
protected $secretKey;
protected $algorithm;
protected $issuer;
protected $expiration;
public function __construct()
{
$this->secretKey = config('jwt.jwt_secret_key');
$this->algorithm = config('jwt.jwt_algorithm');
$this->issuer = config('jwt.jwt_issuer');
$this->expiration = config('jwt.jwt_expiration');
}
/**
* 生成 JWT 令牌
*
* @param array $payload
* @return string
* @throws BusinessException
*/
public function generateToken(array $payload): string
{
$defaultPayload = [
// // —— 注册 Claim ——
'iss' => $this->issuer, // 签发者
// 'sub' => 'user_1001', // 面向的用户
// 'aud' => 'api.gateway.example.com', // 接收方
// 'iat' => time(), // 签发时间
// 'nbf' => time(), // 生效时间
// 'exp' => time() + $this->expiration, // 1 小时后过期
'jti' => bin2hex(random_bytes(16)), // 唯一 ID
// // —— 自定义 Claim ——
// 'uid' => 1001, // 业务用户 ID
// 'roles' => ['admin', 'editor'], // 用户角色
// 'meta' => ['region' => 'CN', 'tier' => 5], // 任意自定义数据
];
$payload = array_merge($defaultPayload, $payload);
try {
return FirebaseJWT::encode($payload, $this->secretKey, $this->algorithm);
} catch (\Exception $e) {
throw new BusinessException("令牌生成失败:" . $e->getMessage(), 500);
}
}
/**
* 验证 JWT 令牌
*
* @param string $token
* @return object
* @throws BusinessException
*/
public function verifyToken(string $token)
{
try {
return FirebaseJWT::decode($token, new Key($this->secretKey, $this->algorithm));
} catch (\Firebase\JWT\ExpiredException $e) {
throw new BusinessException('令牌已过期', 401);
} catch (\Firebase\JWT\SignatureInvalidException $e) {
throw new BusinessException('无效的令牌签名', 401);
} catch (\Firebase\JWT\BeforeValidException $e) {
throw new BusinessException('令牌尚未生效', 401);
} catch (\Exception $e) {
throw new BusinessException('令牌验证失败:' . $e->getMessage(), 400);
}
}
public function describe()
{
/* payload
1. 注册 Claim 详解
Claim 名称 含义 类型 建议取值
iss Issuer,发行者,标识该 JWT 的签发主体 string or URI 你的服务域名或项目标识,比如 https://api.example.com
sub Subject,主题,标识该 JWT 所面向的用户 string or int 用户在你系统里的唯一 ID
aud Audience,受众,标识该 JWT 的接收方 string or array 接收该令牌的服务标识,比如 ["service-a","service-b"]
exp Expiration Time,过期时间,Unix 时间戳,到达此时间后不可用 int time() + 3600(1 小时后过期)
nbf Not Before,生效时间,Unix 时间戳,表示在此时间之前不可用 int time() 或者 time() + 60(1 分钟后生效)
iat Issued At,签发时间,Unix 时间戳 int time()
jti JWT ID,JWT 的唯一标识符,用于去重或一次性令牌 string uniqid('', true) 或者 UUID
注意:exp、nbf、iat 必须是整数(秒级时间戳),否则库会抛类型异常或验证失败。
2. 自定义 Claim
除了上面这些“注册”字段,你可以任意添加,比如:
php
$payload['uid'] = 123; // 业务用户 ID
$payload['roles'] = ['admin','user']; // 权限数组
$payload['feature'] = 'beta'; // 标记某个功能开关
这些字段在你的应用程序里可以自由取用。
*/
}
}
+57
View File
@@ -0,0 +1,57 @@
<?php
namespace app\common\utils;
use support\Db;
class TableInspector
{
/**
* 获取某个表的所有字段信息
*/
public static function getColumns(string $table, ?string $database = null): array
{
$database = $database ?: Db::connection()->getDatabaseName();
$columns = Db::select("
SELECT COLUMN_NAME, DATA_TYPE, COLUMN_TYPE, IS_NULLABLE,
COLUMN_DEFAULT, COLUMN_COMMENT, EXTRA
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
ORDER BY ORDINAL_POSITION
", [$database, $table]);
return array_map(function ($col) {
return [
'name' => $col->COLUMN_NAME,
'type' => $col->DATA_TYPE,
'column_type' => $col->COLUMN_TYPE,
'nullable' => $col->IS_NULLABLE === 'YES',
'default' => $col->COLUMN_DEFAULT,
'comment' => $col->COLUMN_COMMENT,
'extra' => $col->EXTRA,
];
}, $columns);
}
/**
* 获取字段名列表
*/
public static function getColumnNames(string $table, ?string $database = null): array
{
return array_column(self::getColumns($table, $database), 'name');
}
/**
* 获取字段注释 map:字段名 => 注释
*/
public static function getColumnComments(string $table, ?string $database = null): array
{
$columns = self::getColumns($table, $database);
$map = [];
foreach ($columns as $col) {
$map[$col['name']] = $col['comment'];
}
return $map;
}
}
+505
View File
@@ -0,0 +1,505 @@
<?php
namespace app\common\utils;
class Tree
{
// /**
// * 递归构建树形结构
// *
// * @param array $data 数据列表
// * @param int $parentId 父级ID
// * @param string $pidField 父级字段名
// * @param string $idField ID字段名
// * @param int $level 当前层级
// * @return array
// */
// public static function build(array $data, int $parentId = 0, string $pidField = 'parent_id', string $idField = 'id', int $level = 0): array
// {
// $tree = [];
// foreach ($data as $item) {
// if ($item[$pidField] == $parentId) {
// $item['level'] = $level;
// $children = static::build($data, $item[$idField], $pidField, $idField, $level + 1);
// if (!empty($children)) {
// $item['children'] = $children;
// }
// $tree[] = $item;
// }
// }
// return $tree;
// }
// /**
// * 使用引用方式构建树形结构(性能更好)
// *
// * @param array $data 数据列表
// * @param string $pidField 父级字段名
// * @param string $idField ID字段名
// * @return array
// */
// public static function buildWithReference(array $data, string $pidField = 'parent_id', string $idField = 'id'): array
// {
// $items = [];
// $tree = [];
// // 建立以id为索引的数组
// foreach ($data as $item) {
// $item['level'] = 0;
// $items[$item[$idField]] = $item;
// }
// // 构建树形结构
// foreach ($items as $id => $item) {
// if ($item[$pidField] == 0) {
// $tree[] = &$items[$id];
// } else {
// if (isset($items[$item[$pidField]])) {
// $items[$id]['level'] = $items[$item[$pidField]]['level'] + 1;
// if (!isset($items[$item[$pidField]]['children'])) {
// $items[$item[$pidField]]['children'] = [];
// }
// $items[$item[$pidField]]['children'][] = &$items[$id];
// }
// }
// }
// return $tree;
// }
// /**
// * 将树形结构扁平化为列表(带层级前缀)
// *
// * @param array $tree 树形结构数据
// * @param string $prefix 前缀字符
// * @param string $field 显示字段名
// * @param int $level 层级
// * @return array
// */
// public static function flattenWithPrefix(array $tree, string $prefix = '--', string $field = 'name', int $level = 0): array
// {
// $result = [];
// foreach ($tree as $item) {
// $item[$field . '_with_prefix'] = str_repeat($prefix, $item['level']) . $item[$field];
// $result[] = $item;
// if (isset($item['children']) && !empty($item['children'])) {
// $children = static::flattenWithPrefix($item['children'], $prefix, $field, $item['level'] + 1);
// $result = array_merge($result, $children);
// }
// }
// return $result;
// }
// /**
// * 根据父ID查找所有子节点(包括子孙节点)
// *
// * @param array $data 数据列表
// * @param int $parentId 父级ID
// * @param string $pidField 父级字段名
// * @param string $idField ID字段名
// * @return array
// */
// public static function findChildren(array $data, int $parentId, string $pidField = 'parent_id', string $idField = 'id'): array
// {
// $children = [];
// foreach ($data as $item) {
// if ($item[$pidField] == $parentId) {
// $children[] = $item;
// $grandChildren = static::findChildren($data, $item[$idField], $pidField, $idField);
// $children = array_merge($children, $grandChildren);
// }
// }
// return $children;
// }
// /**
// * 获取指定节点的所有父级节点
// *
// * @param array $data 数据列表
// * @param int $id 当前节点ID
// * @param string $pidField 父级字段名
// * @param string $idField ID字段名
// * @return array
// */
// public static function getParents(array $data, int $id, string $pidField = 'parent_id', string $idField = 'id'): array
// {
// $parents = [];
// foreach ($data as $item) {
// if ($item[$idField] == $id) {
// if ($item[$pidField] != 0) {
// $parents[] = $item;
// $parentParents = static::getParents($data, $item[$pidField], $pidField, $idField);
// $parents = array_merge($parents, $parentParents);
// }
// break;
// }
// }
// return $parents;
// }
// /**
// * 获取指定节点的子孙节点ID列表
// *
// * @param array $data 数据列表
// * @param int $parentId 父级ID
// * @param string $pidField 父级字段名
// * @param string $idField ID字段名
// * @return array
// */
// public static function getChildrenIds(array $data, int $parentId, string $pidField = 'parent_id', string $idField = 'id'): array
// {
// $ids = [];
// $children = static::findChildren($data, $parentId, $pidField, $idField);
// foreach ($children as $child) {
// $ids[] = $child[$idField];
// }
// return $ids;
// }
// /**
// * 检查是否有子节点
// *
// * @param array $data 数据列表
// * @param int $parentId 父级ID
// * @param string $pidField 父级字段名
// * @return bool
// */
// public static function hasChildren(array $data, int $parentId, string $pidField = 'parent_id'): bool
// {
// foreach ($data as $item) {
// if ($item[$pidField] == $parentId) {
// return true;
// }
// }
// return false;
// }
// /**
// * 构建带有权限列表的资源树(权限不显示在树结构中)
// *
// * @param array $data 资源数据列表
// * @param int $parentId 父级ID
// * @param string $pidField 父级字段名
// * @param string $idField ID字段名
// * @param string $typeField 类型字段名
// * @param string $permissionType 权限类型标识
// * @param int $level 当前层级
// * @return array
// */
// public static function buildWithAuthList(
// array $data,
// int $parentId = 0,
// string $pidField = 'parent_id',
// string $idField = 'id',
// string $typeField = 'type',
// string $permissionType = 'permission',
// int $level = 0
// ): array {
// $tree = [];
// foreach ($data as $item) {
// // 只处理指定父级的非权限节点
// if ($item[$pidField] == $parentId && $item[$typeField] != $permissionType) {
// $item['level'] = $level;
// // 递归处理子节点(非权限类型)
// $children = static::buildWithAuthList($data, $item[$idField], $pidField, $idField, $typeField, $permissionType, $level + 1);
// if (!empty($children)) {
// $item['children'] = $children;
// }
// // 收集当前节点下的所有权限
// $item['auth_list'] = static::collectDirectPermissions($data, $item[$idField], $pidField, $typeField, $permissionType);
// $tree[] = $item;
// }
// }
// return $tree;
// }
// /**
// * 收集指定节点下的直接权限项(只收集直接子节点中的权限)
// *
// * @param array $data 数据列表
// * @param int $parentId 父级ID
// * @param string $pidField 父级字段名
// * @param string $typeField 类型字段名
// * @param string $permissionType 权限类型标识
// * @return array
// */
// public static function collectDirectPermissions1(
// array $data,
// int $parentId,
// string $pidField = 'parent_id',
// string $typeField = 'type',
// string $permissionType = 'permission'
// ): array {
// $permissions = [];
// foreach ($data as $item) {
// // 收集直接子节点中的权限类型
// if ($item[$pidField] == $parentId && $item[$typeField] == $permissionType) {
// $permissions[] = $item;
// }
// }
// return $permissions;
// }
// /**
// * 使用引用方式构建带有权限列表的资源树(权限不显示在树结构中)
// *
// * @param array $data 资源数据列表
// * @param string $pidField 父级字段名
// * @param string $idField ID字段名
// * @param string $typeField 类型字段名
// * @param string $permissionType 权限类型标识
// * @return array
// */
// public static function buildWithAuthListAndReference(
// array $data,
// string $pidField = 'parent_id',
// string $idField = 'id',
// string $typeField = 'type',
// string $permissionType = 'permission'
// ): array {
// $items = [];
// $tree = [];
// // 建立以id为索引的数组(只包含非权限节点)
// foreach ($data as $item) {
// if ($item[$typeField] != $permissionType) {
// $item['level'] = 0;
// $items[$item[$idField]] = $item;
// }
// }
// // 构建树形结构
// foreach ($items as $id => $item) {
// if ($item[$pidField] == 0) {
// $tree[] = &$items[$id];
// } else {
// if (isset($items[$item[$pidField]])) {
// $items[$id]['level'] = $items[$item[$pidField]]['level'] + 1;
// if (!isset($items[$item[$pidField]]['children'])) {
// $items[$item[$pidField]]['children'] = [];
// }
// $items[$item[$pidField]]['children'][] = &$items[$id];
// }
// }
// }
// // 为每个节点添加权限列表
// foreach ($items as &$item) {
// $item['auth_list'] = static::collectDirectPermissions($data, $item[$idField], $pidField, $typeField, $permissionType);
// }
// return $tree;
// }
// 8.13 add
/**
* 构建前端需要的菜单树结构
*
* @param array $data 服务端菜单数据
* @param int $parentId 父级ID
* @return array
*/
public static function buildMenuTree(array $data, int $parentId = 0): array
{
$tree = [];
foreach ($data as $item) {
// 只处理非权限类型的节点
if ($item['parent_id'] == $parentId && $item['type'] != 'permission') {
// 转换数据结构以匹配前端需要的格式
$menuItem = [
'id' => $item['id'],
'path' => $item['url'] ?? '',
'name' => $item['name'],
'component' => $item['url'] ?? '',
'meta' => [
'title' => $item['name'],
'icon' => $item['icon'] ?? '',
'isHide' => !empty($item['is_hide']),
'isHideTab' => !empty($item['is_hide_tab']),
'keepAlive' => !empty($item['keep_alive']),
]
];
// 收集当前节点下的所有权限
$permissions = static::collectDirectPermissions($data, $item['id']);
if (!empty($permissions)) {
$authList = [];
foreach ($permissions as $permission) {
$authList[] = [
'id' => $permission['id'],
'title' => $permission['name'] ?? '',
'authMark' => $permission['code'] ?? '',
'selected' => isset($permission['selected']) && $permission['selected'] ? true : false
];
}
$menuItem['meta']['authList'] = $authList;
}
// 将服务端额外字段放入meta中
$extraFields = static::getExtraFields($item);
if (!empty($extraFields)) {
$menuItem['meta'] = array_merge($menuItem['meta'], $extraFields);
}
// 递归处理子菜单
$children = static::buildMenuTree($data, $item['id']);
if (!empty($children)) {
$menuItem['children'] = $children;
}
$tree[] = $menuItem;
}
}
return $tree;
}
/**
* 使用引用方式构建前端需要的菜单树结构(性能更好)
*
* @param array $data 服务端菜单数据
* @return array
*/
public static function buildMenuTreeWithReference(array $data): array
{
$items = [];
$tree = [];
// 过滤出菜单类型的节点并转换数据结构
$menuData = array_filter($data, function($item) {
return ($item['type'] ?? '') != 'permission';
});
// 建立以id为索引的数组并转换数据结构
foreach ($menuData as $item) {
$items[$item['id']] = [
'id' => $item['id'],
'path' => $item['url'] ?? '',
'name' => $item['name'],
'component' => $item['url'] ?? '',
'meta' => [
'title' => $item['name'],
'icon' => $item['icon'] ?? '',
'isHide' => !empty($item['is_hide']),
'isHideTab' => !empty($item['is_hide_tab']),
'keepAlive' => !empty($item['keep_alive']),
]
];
// 将服务端额外字段放入meta中
$extraFields = static::getExtraFields($item);
if (!empty($extraFields)) {
$items[$item['id']]['meta'] = array_merge($items[$item['id']]['meta'], $extraFields);
}
}
// 构建树形结构
foreach ($menuData as $item) {
if ($item['parent_id'] == 0) {
$tree[] = &$items[$item['id']];
} else {
if (isset($items[$item['parent_id']])) {
if (!isset($items[$item['parent_id']]['children'])) {
$items[$item['parent_id']]['children'] = [];
}
$items[$item['parent_id']]['children'][] = &$items[$item['id']];
}
}
}
// 为每个节点添加权限列表
foreach ($items as &$item) {
$parentId = $item['id'];
$permissions = static::collectDirectPermissions($data, $parentId);
if (!empty($permissions)) {
$authList = [];
foreach ($permissions as $permission) {
$authList[] = [
'id' => $permission['id'],
'title' => $permission['name'] ?? '',
'authMark' => $permission['code'] ?? ''
];
}
$item['meta']['authList'] = $authList;
}
}
return $tree;
}
/**
* 收集指定节点下的直接权限项(只收集直接子节点中的权限)
*
* @param array $data 数据列表
* @param int $parentId 父级ID
* @return array
*/
public static function collectDirectPermissions(array $data, int $parentId): array
{
$permissions = [];
foreach ($data as $item) {
// 收集直接子节点中的权限类型
if ($item['parent_id'] == $parentId && ($item['type'] ?? '') == 'permission') {
$permissions[] = $item;
}
}
return $permissions;
}
/**
* 获取需要放入meta的额外字段
*
* @param array $item 菜单项
* @return array
*/
public static function getExtraFields(array $item): array
{
$extraFields = [];
$standardFields = [
'id', 'name', 'url', 'icon', 'is_hide', 'is_hide_tab', 'keep_alive', 'level'
];
foreach ($item as $key => $value) {
// 如果不是标准字段且不是auth_list,则放入extraFields
if (!in_array($key, $standardFields) && $key !== 'auth_list') {
// 转换下划线命名到驼峰命名
$camelKey = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $key))));
$extraFields[$camelKey] = $value;
}
}
return $extraFields;
}
}
+194
View File
@@ -0,0 +1,194 @@
<?php
namespace app\common\utils\scaffold;
use Symfony\Component\Filesystem\Filesystem;
use app\common\utils\TableInspector;
class Generate
{
// 配置项
protected $options = [];
public function __construct(array $options = [])
{
if (empty($options)) {
return;
}
$this->options = $options;
}
public function doGenerate()
{
$fs = new Filesystem();
$templateDir = __DIR__ . '/templates/';
$resultStr = '';
if (!empty($this->options['controller'])) {
$controllerPath = __DIR__ . "/../../../{$this->options['controller']['module']}/controller/".$this->rName($this->options['controller']['name'])."Controller.php";
$fs->mkdir(__DIR__ . "/../../../{$this->options['controller']['module']}/controller");
$this->deleteFileIfExists($controllerPath);
$ControllerStub = $this->generateFile($templateDir, 'ControllerStub.stub', $controllerPath, 'controller');
$resultStr .= $ControllerStub;
}
if (!empty($this->options['service'])) {
$servicePath = __DIR__ . "/../../../{$this->options['service']['module']}/service/".$this->rName($this->options['service']['name'])."Service.php";
$fs->mkdir(__DIR__ . "/../../../{$this->options['service']['module']}/service");
$this->deleteFileIfExists($servicePath);
$ServiceStub = $this->generateFile($templateDir, 'ServiceStub.stub', $servicePath, 'service');
$resultStr .= $ServiceStub;
}
if (!empty($this->options['logic'])) {
$logicPath = __DIR__ . "/../../../{$this->options['logic']['module']}/logic/".$this->rName($this->options['logic']['name'])."Logic.php";
$fs->mkdir(__DIR__ . "/../../../{$this->options['logic']['module']}/logic");
$this->deleteFileIfExists($logicPath);
$LogicStub = $this->generateFile($templateDir, 'LogicStub.stub', $logicPath, 'logic');
$resultStr .= $LogicStub;
}
if (!empty($this->options['model'])) {
$modelPath = __DIR__ . "/../../../{$this->options['model']['module']}/model/".$this->rName($this->options['model']['name']).".php";
$fs->mkdir(__DIR__ . "/../../../{$this->options['model']['module']}/model");
$this->deleteFileIfExists($modelPath);
$ModelStub = $this->generateFile($templateDir, 'ModelStub.stub', $modelPath, 'model');
$resultStr .= $ModelStub;
}
if (!empty($this->options['validate'])) {
$validatePath = __DIR__ . "/../../../{$this->options['validate']['module']}/validate/".$this->rName($this->options['validate']['name'])."Validate.php";
$fs->mkdir(__DIR__ . "/../../../{$this->options['validate']['module']}/validate");
$this->deleteFileIfExists($validatePath);
$ValidatorStub = $this->generateFile($templateDir, 'ValidateStub.stub', $validatePath, 'validate');
$resultStr .= $ValidatorStub;
}
return $resultStr ? $resultStr . "<info>文件生成成功!</info> <br/>" : '未生成任何文件';
}
/**
* 根据模板生成文件
*
* @param string $templateDir 模板目录
* @param string $templateFile 模板文件名
* @param string $outputPath 输出文件路径
*/
protected function generateFile($templateDir, $templateFile, $outputPath, $fileType)
{
$templatePath = $templateDir . $templateFile;
if (!file_exists($templatePath)) {
echo "<error>模板文件 {$templateFile} 不存在!</error> \n";
return;
}
$content = file_get_contents($templatePath);
switch ($fileType) {
case 'controller':
$content = str_replace('{{controllerModule}}', $this->options['controller']['module'], $content);
$content = str_replace('{{serviceModule}}', $this->options['service']['module'], $content);
$content = str_replace('{{serviceName}}', $this->rName($this->options['service']['name']), $content);
$content = str_replace('{{controllerName}}', $this->rName($this->options['controller']['name']), $content);
break;
case 'service':
$content = str_replace('{{serviceModule}}', $this->options['service']['module'], $content);
$content = str_replace('{{validateModule}}', $this->options['validate']['module'], $content);
$content = str_replace('{{validateName}}', $this->rName($this->options['validate']['name']), $content);
$content = str_replace('{{modelModule}}', $this->options['model']['module'], $content);
$content = str_replace('{{modelName}}', $this->rName($this->options['model']['name']), $content);
$content = str_replace('{{serviceName}}', $this->rName($this->options['service']['name']), $content);
break;
case 'logic':
$content = str_replace('{{logicModule}}', $this->options['logic']['module'], $content);
$content = str_replace('{{modelModule}}', $this->options['model']['module'], $content);
$content = str_replace('{{modelName}}', $this->rName($this->options['model']['name']), $content);
$content = str_replace('{{logicName}}', $this->rName($this->options['logic']['name']), $content);
break;
case 'model':
$content = str_replace('{{modelModule}}', $this->options['model']['module'], $content);
$content = str_replace('{{modelName}}', $this->rName($this->options['model']['name']), $content);
$content = str_replace('{{table}}', $this->options['table'], $content);
$content = str_replace('{{fillable}}', $this->fillableFields(), $content);
break;
case 'validate':
$content = str_replace('{{validateModule}}', $this->options['validate']['module'], $content);
$content = str_replace('{{validateName}}', $this->rName($this->options['validate']['name']), $content);
break;
}
file_put_contents($outputPath, $content);
return "生成文件: <info>{$outputPath}</info> <br/>";
}
/**
* 设置字段
*
* @param array $fields 字段数组
*/
public function fillableFields()
{
$tableName = $this->options['table'];
$fields = TableInspector::getColumnNames($tableName);
$str = '';
foreach ($fields as $key => $val) {
if ($key < (count($fields)-1)) {
$str .= "'{$val}', ";
} else {
$str .= "'{$val}'";
}
}
$fields = trim($str, '"');
return $fields;
}
/**
* 如果文件存在,删除它
*
* @param string $path 文件路径
*/
protected function deleteFileIfExists($path)
{
if (file_exists($path)) {
// "文件: <comment>{$path}</comment> 已存在,核对后手动删除。\n";
// return;
unlink($path);
echo "删除已存在文件: <comment>{$path}</comment> \n";
}
}
/**
* 设置名称
*/
public function rName($name = '')
{
return ucfirst(camelize($name));
}
}
/**
* 下划线转驼峰
* 思路:
* step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
* step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
*/
function camelize($uncamelized_words, $separator='_') {
$uncamelized_words = $separator . str_replace($separator, " ", strtolower($uncamelized_words));
return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator );
}
/**
* 驼峰命名转下划线命名
* 思路:
* 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
*/
function uncamelize($camelCaps, $separator='_') {
return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
}
@@ -0,0 +1,33 @@
<?php
namespace app\{{controllerModule}}\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\{{serviceModule}}\service\{{serviceName}}Service;
class {{controllerName}}Controller extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new {{serviceName}}Service();
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
// protected function indexFormat($data)
// {
// if (isset($data['created_at']))
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
// if (isset($data['updated_at']))
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
// return $data;
// }
}
@@ -0,0 +1,17 @@
<?php
namespace app\{{logicModule}}\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\{{modelModule}}\model\{{modelName}};
class {{logicName}}Logic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = {{modelName}}::class;
}
@@ -0,0 +1,49 @@
<?php
namespace app\{{modelModule}}\model;
use support\Model;
class {{modelName}} extends Model
{
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'mysql';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = '{{table}}';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = true;
protected $dateFormat = 'U';
/**
* 允许自动填充模型字段
*/
protected $fillable = [{{fillable}}];
/**
* 不允许自动填充模型字段
*/
protected $guarded = [];
}
@@ -0,0 +1,31 @@
<?php
namespace app\{{serviceModule}}\service;
use app\{{validateModule}}\validate\{{validateName}}Validate;
use app\common\traits\crud\CrudServiceTrait;
use app\{{modelModule}}\model\{{modelName}};
class {{serviceName}}Service
{
use CrudServiceTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = {{modelName}}::class;
/**
* 验证器
*/
protected $validator = {{validateName}}Validate::class;
/**
* 获取验证器
*/
public function getValidator()
{
return new $this->validator;
}
}
@@ -0,0 +1,29 @@
<?php
namespace app\{{validateModule}}\validate;
use think\Validate;
class {{validateName}}Validate extends Validate
{
// 规则
protected $rule = [
];
// 提示
protected $message = [
];
// 场景
protected $scene = [
'store' => [
],
'update' => [
]
];
}