From a1731f0076db11e396a8152ef5617464a16306d2 Mon Sep 17 00:00:00 2001 From: yeyixianyang Date: Sun, 7 Dec 2025 10:55:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(routes):=20=E6=B7=BB=E5=8A=A0=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E5=AE=89=E8=A3=85=E5=91=BD=E4=BB=A4=E5=B9=B6=E5=BC=95?= =?UTF-8?q?=E5=85=A5=20Symfony=20Console?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 composer.json 中添加 symfony/console 依赖 - 新增 InstallCommand 控制台命令用于安装路由资源 - 实现服务提供者和配置文件的自动发布 - 自动注册 RouteServiceProvider 到应用配置中 - 支持 Laravel 12.x 和 PHP 8.4+ 版本 - 更新 composer.lock 文件以反映新的依赖关系 --- composer.json | 3 +- composer.lock | 422 ++++++++++++++++++++++++++++++++- src/Console/InstallCommand.php | 68 ++++++ 3 files changed, 491 insertions(+), 2 deletions(-) create mode 100644 src/Console/InstallCommand.php diff --git a/composer.json b/composer.json index c8144da..dbf7892 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "require": { "php": "^8.4", "illuminate/contracts": "^12.0", - "illuminate/support": "^12.41" + "illuminate/support": "^12.41", + "symfony/console": "^8.0" }, "require-dev": { "laravel/pint": "^1.26", diff --git a/composer.lock b/composer.lock index d58c2d3..d58a8a9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d9286198aff7cd8aed5338cc001984a4", + "content-hash": "a7fb30c864a5d3036782534d9fdbd0af", "packages": [ { "name": "carbonphp/carbon-doctrine-types", @@ -645,6 +645,297 @@ }, "time": "2025-11-12T15:46:48+00:00" }, + { + "name": "symfony/console", + "version": "v8.0.0", + "dist": { + "type": "zip", + "url": "https://mirrors.tencent.com/repository/composer/symfony/console/v8.0.0/symfony-console-v8.0.0.zip", + "reference": "307d3cf852f5ead3618ac60ecbedbdd512c348b1", + "shasum": "" + }, + "require": { + "php": ">=8.4", + "symfony/polyfill-mbstring": "^1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.4|^8.0" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^7.4|^8.0", + "symfony/event-dispatcher": "^7.4|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", + "symfony/lock": "^7.4|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/process": "^7.4|^8.0", + "symfony/stopwatch": "^7.4|^8.0", + "symfony/var-dumper": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v8.0.0" + }, + "time": "2025-11-21T13:19:49+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "dist": { + "type": "zip", + "url": "https://mirrors.tencent.com/repository/composer/symfony/deprecation-contracts/v3.6.0/symfony-deprecation-contracts-v3.6.0.zip", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "dist": { + "type": "zip", + "url": "https://mirrors.tencent.com/repository/composer/symfony/polyfill-ctype/v1.33.0/symfony-polyfill-ctype-v1.33.0.zip", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.33.0", + "dist": { + "type": "zip", + "url": "https://mirrors.tencent.com/repository/composer/symfony/polyfill-intl-grapheme/v1.33.0/symfony-polyfill-intl-grapheme-v1.33.0.zip", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + }, + "time": "2025-06-27T09:58:17+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "dist": { + "type": "zip", + "url": "https://mirrors.tencent.com/repository/composer/symfony/polyfill-intl-normalizer/v1.33.0/symfony-polyfill-intl-normalizer-v1.33.0.zip", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "symfony/polyfill-mbstring", "version": "v1.33.0", @@ -874,6 +1165,135 @@ }, "time": "2025-06-23T16:12:55+00:00" }, + { + "name": "symfony/service-contracts", + "version": "v3.6.1", + "dist": { + "type": "zip", + "url": "https://mirrors.tencent.com/repository/composer/symfony/service-contracts/v3.6.1/symfony-service-contracts-v3.6.1.zip", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + }, + "time": "2025-07-15T11:30:57+00:00" + }, + { + "name": "symfony/string", + "version": "v8.0.0", + "dist": { + "type": "zip", + "url": "https://mirrors.tencent.com/repository/composer/symfony/string/v8.0.0/symfony-string-v8.0.0.zip", + "reference": "f929eccf09531078c243df72398560e32fa4cf4f", + "shasum": "" + }, + "require": { + "php": ">=8.4", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-intl-grapheme": "^1.33", + "symfony/polyfill-intl-normalizer": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.4|^8.0", + "symfony/http-client": "^7.4|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^7.4|^8.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v8.0.0" + }, + "time": "2025-09-11T14:37:55+00:00" + }, { "name": "symfony/translation", "version": "v8.0.0", diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php new file mode 100644 index 0000000..70a6c8e --- /dev/null +++ b/src/Console/InstallCommand.php @@ -0,0 +1,68 @@ +components->info('Installing Routes resources.'); + + collect([ + 'Service Provider' => fn () => $this->callSilent('vendor:publish', ['--tag' => 'routes-provider']) == 0, + 'Configuration' => fn () => $this->callSilent('vendor:publish', ['--tag' => 'routes-config']) == 0, + ])->each(fn ($task, $description) => $this->components->task($description, $task)); + + $this->registerRouteServiceProvider(); + + $this->components->info('Jltx Routes scaffolding installed successfully.'); + } + + /** + * Register the Horizon service provider in the application configuration file. + */ + protected function registerRouteServiceProvider(): void + { + $namespace = Str::replaceLast('\\', '', $this->laravel->getNamespace()); + + if (file_exists($this->laravel->bootstrapPath('providers.php'))) { + ServiceProvider::addProviderToBootstrapFile("$namespace\\Providers\\RouteServiceProvider"); + } else { + $appConfig = file_get_contents(config_path('app.php')); + + if (Str::contains($appConfig, $namespace.'\\Providers\\RouteServiceProvider::class')) { + return; + } + + file_put_contents(config_path('app.php'), str_replace( + "{$namespace}\\Providers\EventServiceProvider::class,".PHP_EOL, + "{$namespace}\\Providers\EventServiceProvider::class,".PHP_EOL." {$namespace}\Providers\RouteServiceProvider::class,".PHP_EOL, + $appConfig + )); + } + + file_put_contents(app_path('Providers/RouteServiceProvider.php'), str_replace( + "namespace App\Providers;", + "namespace {$namespace}\Providers;", + file_get_contents(app_path('Providers/RouteServiceProvider.php')) + )); + } +}