123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- const db = require('../util/db');
- const fs = require('fs');
- const path = require('path');
- // 将字符串转换为驼峰命名
- function toCamelCase(str) {
- return str.replace(/[-_](.)/g, (_, c) => c.toUpperCase());
- }
- // 根据关系类型获取对应的方法名
- function getRelationshipMethod(type) {
- const typeMap = {
- 'HAS_MANY': 'hasMany',
- 'BELONGS_TO': 'belongsTo',
- 'HAS_ONE': 'hasOne',
- 'BELONGS_TO_MANY': 'belongsToMany',
- 'MANY_TO_MANY': 'belongsToMany',
- 'MANY_TO_MANY_INVERSE': 'belongsToMany',
- 'MORPH_ONE': 'morphOne',
- 'MORPH_MANY': 'morphMany',
- 'MORPH_TO': 'morphTo',
- 'MORPH_TO_MANY': 'morphToMany',
- 'MORPHED_BY_MANY': 'morphedByMany',
- 'HAS_MANY_THROUGH': 'hasManyThrough',
- 'HAS_ONE_THROUGH': 'hasOneThrough',
- 'HAS_ONE_OF_MANY': 'hasOneOfMany',
- 'MORPH_TO_ONE': 'morphToOne',
- 'HAS_MANY_THROUGH_MANY': 'hasManyThroughMany'
- };
- return typeMap[type] || type;
- }
- // 生成关系方法的代码
- function generateMethodCode(data) {
- const {title, type, remark, args} = data;
- const argsObj = typeof args === 'string' ? JSON.parse(args) : args;
- const relationshipMethod = getRelationshipMethod(type);
-
- // 构建方法参数
- const methodArgs = [];
-
- // 基本参数处理
- if (argsObj.related) {
- // 只使用模型名称
- const modelName = argsObj.related.split('\\').pop();
- methodArgs.push(`${modelName}::class`);
- }
-
- // 多态关系参数处理
- if (relationshipMethod.includes('morph')) {
- if (relationshipMethod === 'morphTo') {
- // morphTo 方法的特殊处理
- if (argsObj.name) {
- methodArgs.push(`'${argsObj.name}'`);
- }
- if (argsObj.type && argsObj.id) {
- methodArgs.push(`'${argsObj.type}'`);
- methodArgs.push(`'${argsObj.id}'`);
- }
- // 支持 morphMap 类型数组
- if (argsObj.morphMap && Array.isArray(argsObj.morphMap)) {
- const morphMapStr = argsObj.morphMap.map(type => `'${type}'`).join(', ');
- methodArgs.push(`[${morphMapStr}]`);
- }
- } else if (relationshipMethod === 'morphToMany' || relationshipMethod === 'morphedByMany') {
- // morphToMany 和 morphedByMany 的特殊处理
- if (argsObj.name) {
- methodArgs.push(`'${argsObj.name}'`);
- }
- if (argsObj.table) {
- methodArgs.push(`'${argsObj.table}'`);
- }
- if (argsObj.foreignPivotKey) {
- methodArgs.push(`'${argsObj.foreignPivotKey}'`);
- }
- if (argsObj.relatedPivotKey) {
- methodArgs.push(`'${argsObj.relatedPivotKey}'`);
- }
- if (argsObj.parentKey) {
- methodArgs.push(`'${argsObj.parentKey}'`);
- }
- if (argsObj.relatedKey) {
- methodArgs.push(`'${argsObj.relatedKey}'`);
- }
- if (argsObj.morphType) {
- methodArgs.push(`'${argsObj.morphType}'`);
- }
- if (argsObj.morphClass) {
- // 只使用模型名称
- const morphClassName = argsObj.morphClass.split('\\').pop();
- methodArgs.push(`${morphClassName}::class`);
- }
- } else if (relationshipMethod === 'morphToOne') {
- // morphToOne 处理
- if (argsObj.name) {
- methodArgs.push(`'${argsObj.name}'`);
- }
- if (argsObj.type) {
- methodArgs.push(`'${argsObj.type}'`);
- }
- if (argsObj.id) {
- methodArgs.push(`'${argsObj.id}'`);
- }
- if (argsObj.morphClass) {
- const morphClassName = argsObj.morphClass.split('\\').pop();
- methodArgs.push(`${morphClassName}::class`);
- }
- if (argsObj.localKey) {
- methodArgs.push(`'${argsObj.localKey}'`);
- }
- } else {
- // morphOne 和 morphMany 处理
- if (argsObj.name) {
- methodArgs.push(`'${argsObj.name}'`);
- }
- if (argsObj.type) {
- methodArgs.push(`'${argsObj.type}'`);
- }
- if (argsObj.id) {
- methodArgs.push(`'${argsObj.id}'`);
- }
- if (argsObj.localKey) {
- methodArgs.push(`'${argsObj.localKey}'`);
- }
- if (argsObj.morphClass) {
- // 只使用模型名称
- const morphClassName = argsObj.morphClass.split('\\').pop();
- methodArgs.push(`${morphClassName}::class`);
- }
- }
- } else {
- // 普通关系参数处理
- if (argsObj.foreignKey) {
- methodArgs.push(`'${argsObj.foreignKey}'`);
- }
- if (argsObj.localKey) {
- methodArgs.push(`'${argsObj.localKey}'`);
- }
-
- // belongsTo 额外参数
- if (relationshipMethod === 'belongsTo' && argsObj.ownerKey) {
- methodArgs.push(`'${argsObj.ownerKey}'`);
- }
-
- // belongsToMany 额外参数
- if (relationshipMethod === 'belongsToMany') {
- if (argsObj.table) {
- methodArgs.push(`'${argsObj.table}'`);
- }
- if (argsObj.foreignPivotKey) {
- methodArgs.push(`'${argsObj.foreignPivotKey}'`);
- }
- if (argsObj.relatedPivotKey) {
- methodArgs.push(`'${argsObj.relatedPivotKey}'`);
- }
- if (argsObj.parentKey) {
- methodArgs.push(`'${argsObj.parentKey}'`);
- }
- if (argsObj.relatedKey) {
- methodArgs.push(`'${argsObj.relatedKey}'`);
- }
- }
-
- // through 关系额外参数
- if (relationshipMethod.includes('Through')) {
- if (argsObj.through) {
- // 只使用模型名称
- const throughModelName = argsObj.through.split('\\').pop();
- methodArgs.push(`${throughModelName}::class`);
- }
- if (argsObj.firstKey) {
- methodArgs.push(`'${argsObj.firstKey}'`);
- }
- if (argsObj.secondKey) {
- methodArgs.push(`'${argsObj.secondKey}'`);
- }
- if (argsObj.localKey) {
- methodArgs.push(`'${argsObj.localKey}'`);
- }
- if (argsObj.secondLocalKey) {
- methodArgs.push(`'${argsObj.secondLocalKey}'`);
- }
- if (argsObj.farKey) {
- methodArgs.push(`'${argsObj.farKey}'`);
- }
- }
-
- // hasManyThroughMany 特殊参数
- if (relationshipMethod === 'hasManyThroughMany') {
- if (argsObj.through) {
- const throughModelName = argsObj.through.split('\\').pop();
- methodArgs.push(`${throughModelName}::class`);
- }
- if (argsObj.firstKey) {
- methodArgs.push(`'${argsObj.firstKey}'`);
- }
- if (argsObj.secondKey) {
- methodArgs.push(`'${argsObj.secondKey}'`);
- }
- if (argsObj.localKey) {
- methodArgs.push(`'${argsObj.localKey}'`);
- }
- if (argsObj.secondLocalKey) {
- methodArgs.push(`'${argsObj.secondLocalKey}'`);
- }
- }
-
- // hasOneOfMany 特殊参数
- if (relationshipMethod === 'hasOneOfMany') {
- if (argsObj.aggregate) {
- methodArgs.push(`'${argsObj.aggregate}'`);
- }
- if (argsObj.column) {
- methodArgs.push(`'${argsObj.column}'`);
- }
- }
- }
- // 构建方法链
- let methodChain = relationshipMethod;
-
- // 软删除相关
- if (argsObj.withTrashed) {
- methodChain += '->withTrashed()';
- } else if (argsObj.onlyTrashed) {
- methodChain += '->onlyTrashed()';
- } else {
- methodChain += '';
- }
-
- // 生成方法代码
- return ` /**
- * @Author FelixYin
- * @description ${remark}
- */
- public function ${toCamelCase(title)}()
- {
- return $this->${methodChain}(${methodArgs.join(', ')});
- }`;
- }
- // 查找类的边界(开始和结束行)
- function findClassBoundaries(lines) {
- let classStartLine = -1;
- let classEndLine = -1;
- let braceCount = 0;
- let foundClass = false;
- for (let i = 0; i < lines.length; i++) {
- const line = lines[i];
- if (line.includes('class ')) {
- classStartLine = i;
- foundClass = true;
- }
- if (foundClass) {
- braceCount += (line.match(/{/g) || []).length;
- braceCount -= (line.match(/}/g) || []).length;
- if (braceCount === 0 && line.includes('}')) {
- classEndLine = i;
- break;
- }
- }
- }
- if (classStartLine === -1 || classEndLine === -1) {
- throw new Error('无效的PHP类格式');
- }
- return { start: classStartLine, end: classEndLine };
- }
- // 在类中查找特定方法
- function findMethodInClass(lines, methodName, classStart, classEnd) {
- let methodStartLine = -1;
- let methodEndLine = -1;
- let braceCount = 0;
- let inMethod = false;
- // 向上查找注释的起始位置
- function findCommentStart(startLine) {
- let line = startLine;
- while (line >= classStart) {
- if (!lines[line].trim().startsWith('*') && !lines[line].trim().startsWith('/*')) {
- return line + 1;
- }
- line--;
- }
- return startLine;
- }
- for (let i = classStart; i <= classEnd; i++) {
- const line = lines[i].trim();
- if (line.startsWith('public function') && line.includes(`function ${methodName}`)) {
- methodStartLine = findCommentStart(i - 1);
- inMethod = true;
- }
- if (inMethod) {
- braceCount += (line.match(/{/g) || []).length;
- braceCount -= (line.match(/}/g) || []).length;
- if (braceCount === 0 && line.includes('}')) {
- methodEndLine = i;
- break;
- }
- }
- }
- if (methodStartLine === -1 || methodEndLine === -1) {
- return null;
- }
- return { start: methodStartLine, end: methodEndLine };
- }
- // 更新模型文件
- async function updateModelFile(modelPath, methodCode, title) {
- try {
- // 检查文件是否存在
- if (!fs.existsSync(modelPath)) {
- console.error(`未找到模型文件: ${modelPath}`);
- return;
- }
- // 读取文件内容并按行分割
- let lines = fs.readFileSync(modelPath, 'utf8').split('\n');
-
- // 查找类的边界
- const classBoundaries = findClassBoundaries(lines);
-
- // 在类边界内查找现有方法
- const existingMethod = findMethodInClass(lines, toCamelCase(title), classBoundaries.start, classBoundaries.end);
-
- // 将新方法代码分割成行
- const newLines = methodCode.split('\n');
-
- if (existingMethod) {
- // 替换现有方法
- lines.splice(existingMethod.start, existingMethod.end - existingMethod.start + 1);
-
- // 确保方法前有一个空行
- if (existingMethod.start === 0 || lines[existingMethod.start - 1].trim() !== '') {
- lines.splice(existingMethod.start, 0, '', ...newLines);
- } else {
- lines.splice(existingMethod.start, 0, ...newLines);
- }
- } else {
- // 在类结束前添加新方法
- let insertPosition = classBoundaries.end;
-
- // 如果前一行不是空行,添加一个空行
- if (lines[insertPosition - 1].trim() !== '') {
- lines.splice(insertPosition, 0, '', ...newLines);
- } else {
- // 如果前一行是空行,直接添加方法
- lines.splice(insertPosition, 0, ...newLines);
- }
- }
- // 清理多余的空行
- let cleanedLines = [];
- let lastLineEmpty = false;
- for (let i = 0; i < lines.length; i++) {
- const line = lines[i].trim();
- const isEmpty = line === '';
- // 如果当前行不为空,或者(当前行为空但前一行不为空)
- if (!isEmpty || !lastLineEmpty) {
- cleanedLines.push(lines[i]);
- }
- lastLineEmpty = isEmpty;
- }
- // 将更新后的内容写回文件
- fs.writeFileSync(modelPath, cleanedLines.join('\n'), 'utf8');
- console.log(`已更新模型文件: ${modelPath}`);
- } catch (error) {
- console.error(`更新模型文件 ${modelPath} 时出错:`, error);
- }
- }
- // 主函数
- async function main() {
- try {
- // 查询关系数据
- const [rows] = await db.query('SELECT * FROM admin_relationships');
- console.log('找到的关系数量:', rows.length);
-
- // 遍历每个关系
- for (const relation of rows) {
- console.log('正在处理关系:', relation.model);
-
- // 将模型命名空间转换为文件路径
- const modelFile = relation.model
- .replace('App\\Models\\', '')
- .replace(/\\/g, '/')
- + '.php';
-
- // 构建完整的模型文件路径
- const modelPath = path.join('/home/fy/work/xiaoding/owl-admin/app/Models', modelFile);
-
- // 生成关系方法代码并更新模型文件
- const methodCode = generateMethodCode(relation);
- await updateModelFile(modelPath, methodCode, relation.title);
- }
-
- console.log('已完成模型关系的更新');
- process.exit(0);
- } catch (error) {
- console.error('发生错误:', error);
- process.exit(1);
- }
- }
- // 执行主函数
- main();
|