From 420445a9c7da77bb5330ce74bda8f39333dd6b0c Mon Sep 17 00:00:00 2001 From: agis Date: Thu, 17 Sep 2026 21:56:54 +0700 Subject: [PATCH 1/2] feat(deps): bump fork vendor floor to Symfony 7 + carbon 3 (task 4.0a) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First slice of the Wave-4 enabler (task 4.0): raise the fork's vendor floor toward Laravel 13's so illuminate/*:^13 becomes co-installable later. symfony/* ~6.4 → ^7.4, symfony/var-dumper ~6.4 → ^7.4. carbon is dragged to ^3.8.4 by necessity: carbon 2 caps symfony/translation at ^6, so it cannot coexist with symfony/translation ^7. monolog stays ^2 (no symfony coupling; deferred to a later slice with illuminate/log:^13). Fork code made compatible with the new floor (fork suite: 1647 green, 0 signature breaks, unchanged from baseline): - Console\Command::execute(): mixed → int (Symfony 7 typed return). - Console\Application: drop fluent setAutoExit() override (parent is now : void) and move setAutoExit(false) out of the make() chain; add() gets : ?Command return type. - Foundation\Application::terminate / Http\StackedHttpKernel::terminate get : void (TerminableInterface typed return). - Http\Request::createFromBase: for JSON, replace() into the existing InputBag instead of assigning a ParameterBag (Symfony 7 typed $request->request). - Cache Repository/TaggedCache getMinutes(): carbon 3 diffInMinutes() is now signed + float → use now()->diffInMinutes($ttl) and cast to int (was instance($ttl)->diffInMinutes(), which went negative for future TTLs and silently skipped the write — also the root cause of the CachedRouting misses). - FoundationArtisanTest: mock a real Command (find(): Command) and capture the ArrayInput via the matcher, since run(): int no longer returns the input. Co-Authored-By: Claude Opus 4.8 (1M context) --- composer.json | 32 +++++++++---------- src/Illuminate/Cache/Repository.php | 2 +- src/Illuminate/Cache/TaggedCache.php | 2 +- src/Illuminate/Console/Application.php | 21 +++--------- src/Illuminate/Console/Command.php | 2 +- src/Illuminate/Foundation/Application.php | 2 +- .../Foundation/Http/StackedHttpKernel.php | 2 +- src/Illuminate/Http/Request.php | 9 +++++- tests/Foundation/FoundationArtisanTest.php | 12 ++++--- 9 files changed, 40 insertions(+), 44 deletions(-) diff --git a/composer.json b/composer.json index 3bbc1211..3622b0e2 100755 --- a/composer.json +++ b/composer.json @@ -16,24 +16,24 @@ "ircmaxell/password-compat": "~1.0", "laravel/serializable-closure": "^1.2", "monolog/monolog": "^2.10", - "nesbot/carbon": "^2.71", + "nesbot/carbon": "^3.8.4", "opis/closure": "~3.6", "pda/pheanstalk": "~4.0", "predis/predis": "^2.4.1", - "symfony/browser-kit": "~6.4", - "symfony/console": "~6.4", - "symfony/css-selector": "~6.4", - "symfony/dom-crawler": "~6.4", - "symfony/error-handler": "~6.4", - "symfony/event-dispatcher": "~6.4", - "symfony/finder": "~6.4", - "symfony/http-foundation": "~6.4", - "symfony/http-kernel": "~6.4", - "symfony/mailer": "^6.4", - "symfony/mime": "~6.4", - "symfony/process": "~6.4", - "symfony/routing": "~6.4", - "symfony/translation": "~6.4", + "symfony/browser-kit": "^7.4", + "symfony/console": "^7.4", + "symfony/css-selector": "^7.4", + "symfony/dom-crawler": "^7.4", + "symfony/error-handler": "^7.4", + "symfony/event-dispatcher": "^7.4", + "symfony/finder": "^7.4", + "symfony/http-foundation": "^7.4", + "symfony/http-kernel": "^7.4", + "symfony/mailer": "^7.4", + "symfony/mime": "^7.4", + "symfony/process": "^7.4", + "symfony/routing": "^7.4", + "symfony/translation": "^7.4", "voku/portable-ascii": "2.0.3" }, "replace": { @@ -71,7 +71,7 @@ "phpspec/prophecy-phpunit": "~2.0", "phpunit/phpunit": "~9.6", "rector/rector": "^2.1", - "symfony/var-dumper": "~6.4" + "symfony/var-dumper": "^7.4" }, "autoload": { "classmap": [ diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index 5a0518d1..5fefacfa 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -260,7 +260,7 @@ protected function getMinutes($duration) $duration = Carbon::now()->add($duration); } - $fromNow = Carbon::instance($duration)->diffInMinutes(); + $fromNow = (int) Carbon::now()->diffInMinutes($duration); return $fromNow > 0 ? $fromNow : null; } diff --git a/src/Illuminate/Cache/TaggedCache.php b/src/Illuminate/Cache/TaggedCache.php index bddccdf5..29aaad7a 100644 --- a/src/Illuminate/Cache/TaggedCache.php +++ b/src/Illuminate/Cache/TaggedCache.php @@ -237,7 +237,7 @@ protected function getMinutes($duration) $duration = Carbon::now()->add($duration); } - $fromNow = Carbon::instance($duration)->diffInMinutes(); + $fromNow = (int) Carbon::now()->diffInMinutes($duration); return $fromNow > 0 ? $fromNow : null; } diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index 1de25673..23cc4cd0 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -45,8 +45,9 @@ public static function make($app) $console = with($console = new static('Laravel Framework', $app::VERSION)) ->setLaravel($app) - ->setExceptionHandler($app['exception']) - ->setAutoExit(false); + ->setExceptionHandler($app['exception']); + + $console->setAutoExit(false); $app->instance('artisan', $console); @@ -108,7 +109,7 @@ public function call($command, array $parameters = array(), ?OutputInterface $ou * @return \Symfony\Component\Console\Command\Command */ #[\Override] - public function add(SymfonyCommand $command) + public function add(SymfonyCommand $command): ?SymfonyCommand { if ($command instanceof Command) { @@ -229,18 +230,4 @@ public function setLaravel($laravel) return $this; } - /** - * Set whether the Console app should auto-exit when done. - * - * @param bool $boolean - * @return $this - */ - #[\Override] - public function setAutoExit($boolean) - { - parent::setAutoExit($boolean); - - return $this; - } - } diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index feba65d2..c81337b4 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -108,7 +108,7 @@ public function run(InputInterface $input, OutputInterface $output): int * @param \Symfony\Component\Console\Output\OutputInterface $output * @return mixed */ - protected function execute(InputInterface $input, OutputInterface $output): mixed + protected function execute(InputInterface $input, OutputInterface $output): int { // Prefer handle() (L13 idiom); fire() is the L4.2 fallback that dies at the Console swap. // ponytail: fork mirror of stock Command's handle-or-__invoke resolution; app-side is grep-guarded. diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 72448dc1..e461fe62 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -802,7 +802,7 @@ public function dispatch(Request $request) * @param \Symfony\Component\HttpFoundation\Response $response * @return void */ - public function terminate(SymfonyRequest $request, SymfonyResponse $response) + public function terminate(SymfonyRequest $request, SymfonyResponse $response): void { $this->callFinishCallbacks($request, $response); diff --git a/src/Illuminate/Foundation/Http/StackedHttpKernel.php b/src/Illuminate/Foundation/Http/StackedHttpKernel.php index b010093e..1849bb6b 100644 --- a/src/Illuminate/Foundation/Http/StackedHttpKernel.php +++ b/src/Illuminate/Foundation/Http/StackedHttpKernel.php @@ -23,7 +23,7 @@ public function handle(Request $request, $type = HttpKernelInterface::MAIN_REQUE return $this->app->handle($request, $type, $catch); } - public function terminate(Request $request, Response $response) + public function terminate(Request $request, Response $response): void { $prevKernel = null; diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index c190e75e..14947e00 100755 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -591,7 +591,14 @@ public static function createFromBase(SymfonyRequest $request) $request->content = $content; - $request->request = $request->getInputSource(); + if ($request->isJson()) + { + $request->request->replace($request->json()->all()); + } + else + { + $request->request = $request->getInputSource(); + } return $request; } diff --git a/tests/Foundation/FoundationArtisanTest.php b/tests/Foundation/FoundationArtisanTest.php index 01147eee..573e377b 100755 --- a/tests/Foundation/FoundationArtisanTest.php +++ b/tests/Foundation/FoundationArtisanTest.php @@ -25,16 +25,18 @@ public function testArtisanIsCalledWithProperArguments(): void $artisan->expects($this->once())->method('getArtisan')->willReturn( $console = m::mock('Illuminate\Console\Application[find]') ); - $console->shouldReceive('find')->once()->with('foo')->andReturn($command = m::mock('StdClass')); + $console->shouldReceive('find')->once()->with('foo')->andReturn($command = m::mock(\Symfony\Component\Console\Command\Command::class)); $command->shouldReceive('run')->once()->with(m::type(ArrayInput::class), m::type( NullOutput::class - ))->andReturnUsing(function($input, $output) + ))->andReturnUsing(function($input, $output) use (&$captured) { - return $input; + $captured = $input; + + return 0; }); - $input = $artisan->call('foo', ['--bar' => 'baz']); - $this->assertEquals('baz', $input->getParameterOption('--bar')); + $artisan->call('foo', ['--bar' => 'baz']); + $this->assertEquals('baz', $captured->getParameterOption('--bar')); } } From 848145211633951d3cdcc72556b15acde1e406a3 Mon Sep 17 00:00:00 2001 From: agis Date: Thu, 17 Sep 2026 22:03:18 +0700 Subject: [PATCH 2/2] feat(deps): bump monolog to 3 + fix Log wiring (task 4.0a) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes the vendor-floor bump for task 4.0: monolog/monolog ^2.10 → ^3.10 (→ 3.12), reaching Laravel 13's floor. Log\Logger already parsed levels via the Monolog\Logger::* constants (still present in monolog 3) and logs with string levels (monolog 3 log() still accepts them), so it needed no change — verified by a smoke over useFiles()/log()/level-filtering under monolog 3. Fixes a latent wiring bug in LogServiceProvider surfaced by monolog 3's typed constructor: `use Monolog\Logger` shadowed the same-namespace Illuminate\Log\Logger, so `new Logger(new Logger($env), $events)` built two Monolog loggers and passed a Monolog logger where a string name is required. (Latent since the 3.5 Writer→Logger rename created the name collision; the app runs an older tag and the fork suite doesn't cover register(), so it never fired.) Alias the import to MonologLogger so the outer resolves to the fork wrapper again. Fork suite: 1647 green, 0 signature breaks. Co-Authored-By: Claude Opus 4.8 (1M context) --- composer.json | 2 +- src/Illuminate/Log/LogServiceProvider.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 3622b0e2..4e23657d 100755 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "filp/whoops": "~2.11", "ircmaxell/password-compat": "~1.0", "laravel/serializable-closure": "^1.2", - "monolog/monolog": "^2.10", + "monolog/monolog": "^3.10", "nesbot/carbon": "^3.8.4", "opis/closure": "~3.6", "pda/pheanstalk": "~4.0", diff --git a/src/Illuminate/Log/LogServiceProvider.php b/src/Illuminate/Log/LogServiceProvider.php index dba98093..3292aa7e 100755 --- a/src/Illuminate/Log/LogServiceProvider.php +++ b/src/Illuminate/Log/LogServiceProvider.php @@ -1,6 +1,6 @@ app['env']), $this->app['events'] + new MonologLogger($this->app['env']), $this->app['events'] ); // Once we have an instance of the logger we'll bind it as an instance into