|
|
@@ -0,0 +1,171 @@
|
|
|
+<?php
|
|
|
+declare(strict_types=1);
|
|
|
+
|
|
|
+namespace SixShop\MakerBundle\Generator;
|
|
|
+
|
|
|
+use Symfony\Component\Console\Style\SymfonyStyle;
|
|
|
+
|
|
|
+class ComposerGenerator
|
|
|
+{
|
|
|
+ private string $templatePath;
|
|
|
+
|
|
|
+ public function __construct()
|
|
|
+ {
|
|
|
+ $this->templatePath = __DIR__ . '/../../templates/composer.json.tpl.php';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户输入的包信息
|
|
|
+ */
|
|
|
+ public function gatherPackageInfo(SymfonyStyle $io): ?array
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // 获取包名
|
|
|
+ $packageName = $io->ask('请输入Composer包名 (例如: six-shop/hello 或sixdec/abc)');
|
|
|
+
|
|
|
+ if (empty($packageName)) {
|
|
|
+ throw new \InvalidArgumentException('包名不能为空!');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证包名格式
|
|
|
+ if (!preg_match('/^[a-z0-9-_]+\/[a-z0-9-_]+$/', $packageName)) {
|
|
|
+ throw new \InvalidArgumentException('包名格式不正确! 正确格式: six-shop/hello 或sixdec/abc');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取包描述
|
|
|
+ $description = $io->ask('请输入包描述 (可选)', 'A SixShop extension package');
|
|
|
+
|
|
|
+ // 获取命名空间
|
|
|
+ $defaultNamespace = $this->generateDefaultNamespace($packageName);
|
|
|
+ $namespace = $io->ask('请输入命名空间 (例如: SixShop\\\\Hello)', $defaultNamespace);
|
|
|
+
|
|
|
+ // 获取扩展ID
|
|
|
+ $defaultId = str_replace('/', '-', $packageName);
|
|
|
+ $id = $io->ask('请输入扩展ID (例如: six-shop-hello)', $defaultId);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'packageName' => $packageName,
|
|
|
+ 'description' => $description,
|
|
|
+ 'namespace' => $namespace,
|
|
|
+ 'id' => $id
|
|
|
+ ];
|
|
|
+ } catch (\InvalidArgumentException $e) {
|
|
|
+ $io->error($e->getMessage());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成默认命名空间
|
|
|
+ */
|
|
|
+ private function generateDefaultNamespace(string $packageName): string
|
|
|
+ {
|
|
|
+ $parts = explode('/', $packageName);
|
|
|
+ $vendor = $this->convertToNamespace($parts[0]);
|
|
|
+ $package = $this->convertToNamespace($parts[1]);
|
|
|
+ return $vendor . '\\\\' . $package;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将字符串转换为命名空间格式
|
|
|
+ */
|
|
|
+ private function convertToNamespace(string $string): string
|
|
|
+ {
|
|
|
+ $parts = explode('-', $string);
|
|
|
+ $parts = array_map('ucfirst', $parts);
|
|
|
+ return implode('', $parts);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成composer.json内容
|
|
|
+ */
|
|
|
+ public function generateContent(string $packageName, string $namespace, string $id, string $description = 'A SixShop extension package'): string
|
|
|
+ {
|
|
|
+ if (!file_exists($this->templatePath)) {
|
|
|
+ throw new \RuntimeException('模板文件不存在: ' . $this->templatePath);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 准备模板变量
|
|
|
+ $name = $packageName;
|
|
|
+
|
|
|
+ // 生成composer.json内容
|
|
|
+ ob_start();
|
|
|
+ include $this->templatePath;
|
|
|
+ return ob_get_clean();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存composer.json文件到指定目录
|
|
|
+ */
|
|
|
+ public function saveComposerFile(string $packageName, string $content, SymfonyStyle $io): bool
|
|
|
+ {
|
|
|
+ // 获取vendor上级目录并构建路径: runtime/extension/{package-name}/
|
|
|
+ $vendorDir = dirname(__DIR__, 5); // 从当前文件位置向上5级到vendor上级目录
|
|
|
+ $extensionDir = $vendorDir . '/runtime/extension/' . $packageName;
|
|
|
+
|
|
|
+ // 确保目录存在
|
|
|
+ if (!is_dir($extensionDir)) {
|
|
|
+ if (!mkdir($extensionDir, 0755, true)) {
|
|
|
+ $io->error('无法创建目录: ' . $extensionDir);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $outputPath = $extensionDir . '/composer.json';
|
|
|
+ if (file_put_contents($outputPath, $content) !== false) {
|
|
|
+ $io->success('composer.json 文件已成功生成: ' . $outputPath);
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ $io->error('无法写入文件: ' . $outputPath);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 完整的生成和保存流程
|
|
|
+ */
|
|
|
+ public function createComposerJson(string $packageName, string $namespace, string $id, string $description, SymfonyStyle $io): bool
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // 生成内容
|
|
|
+ $content = $this->generateContent($packageName, $namespace, $id, $description);
|
|
|
+
|
|
|
+ // 输出生成的内容
|
|
|
+ $io->section('生成的 composer.json 内容:');
|
|
|
+ $io->text($content);
|
|
|
+
|
|
|
+ // 询问是否保存文件
|
|
|
+ if ($io->confirm('是否将内容保存到 composer.json 文件?', true)) {
|
|
|
+ return $this->saveComposerFile($packageName, $content, $io);
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ $io->error('生成 composer.json 时发生错误: ' . $e->getMessage());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 完整的从用户输入到生成文件的工作流
|
|
|
+ */
|
|
|
+ public function createComposerFromUserInput(SymfonyStyle $io): bool
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // 获取用户输入
|
|
|
+ $packageInfo = $this->gatherPackageInfo($io);
|
|
|
+
|
|
|
+ // 生成composer.json
|
|
|
+ return $this->createComposerJson(
|
|
|
+ $packageInfo['packageName'],
|
|
|
+ $packageInfo['namespace'],
|
|
|
+ $packageInfo['id'],
|
|
|
+ $packageInfo['description'],
|
|
|
+ $io
|
|
|
+ );
|
|
|
+ } catch (\InvalidArgumentException $e) {
|
|
|
+ $io->error($e->getMessage());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|