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();