From 59ba901452a21861a02bd933652fc12c10d094ef Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Mon, 22 Sep 2025 16:09:20 -0400 Subject: [PATCH 1/8] remove provider --- src/Illuminate/Support/ServiceProvider.php | 45 +++++++++++++++++++ tests/Support/SupportServiceProviderTest.php | 46 ++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/Illuminate/Support/ServiceProvider.php b/src/Illuminate/Support/ServiceProvider.php index ce2b526d2be1..7b11a0423115 100755 --- a/src/Illuminate/Support/ServiceProvider.php +++ b/src/Illuminate/Support/ServiceProvider.php @@ -572,6 +572,51 @@ public static function addProviderToBootstrapFile(string $provider, ?string $pat $content = 'getBootstrapProvidersPath(); + + if (! file_exists($path)) { + return false; + } + + if (function_exists('opcache_invalidate')) { + opcache_invalidate($path, true); + } + + $providersToRemove = Arr::wrap($providersToRemove); + + $providers = (new Collection(require $path)) + ->unique() + ->sort() + ->values() + ->when( + $strict, + static fn (Collection $providerCollection) => $providerCollection->reject(fn (string $p) => in_array($p, $providersToRemove, true)), + static fn (Collection $providerCollection) => $providerCollection->reject(fn (string $p) => Str::contains($p, $providersToRemove)) + ) + ->map(fn ($p) => ' '.$p.'::class,') + ->implode(PHP_EOL); + + $content = 'boot(); $two = new ServiceProviderForTestingTwo($app); $two->boot(); + + $this->tempFile = __DIR__ . '/providers.php'; } protected function tearDown(): void { m::close(); + if ($this->tempFile && file_exists($this->tempFile)) { + @unlink($this->tempFile); + } } public function testPublishableServiceProviders() @@ -191,6 +197,46 @@ public function testLoadTranslationsFromWithNamespace() $provider = new ServiceProviderForTestingOne($this->app); $provider->loadTranslationsFrom(__DIR__.'/translations', 'namespace'); } + + public function test_can_remove_provider() + { + + $r = file_put_contents($this->tempFile, $contents = <<< PHP +tempFile, true); + + // Should have deleted nothing + $this->assertSame($contents, trim(file_get_contents($this->tempFile))); + + ServiceProvider::removeProviderFromBootstrapFile('App\Providers\TelescopeServiceProvider', $this->tempFile, true); + + $this->assertSame(<<< PHP +tempFile))); + + ServiceProvider::removeProviderFromBootstrapFile('AppServiceProvider', $this->tempFile); + + $this->assertSame(<<< 'PHP' +tempFile))); + } } class ServiceProviderForTestingOne extends ServiceProvider From 271f8588b5b9e21a3cca1ebe25abd6104aefa336 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Mon, 22 Sep 2025 17:22:13 -0400 Subject: [PATCH 2/8] string equals string ignoring line endings --- tests/Support/SupportServiceProviderTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Support/SupportServiceProviderTest.php b/tests/Support/SupportServiceProviderTest.php index 58d5182bddaa..4d37b3d73adf 100644 --- a/tests/Support/SupportServiceProviderTest.php +++ b/tests/Support/SupportServiceProviderTest.php @@ -201,7 +201,7 @@ public function testLoadTranslationsFromWithNamespace() public function test_can_remove_provider() { - $r = file_put_contents($this->tempFile, $contents = <<< PHP + file_put_contents($this->tempFile, $contents = <<< PHP tempFile, true); // Should have deleted nothing - $this->assertSame($contents, trim(file_get_contents($this->tempFile))); + $this->assertStringEqualsStringIgnoringLineEndings($contents, trim(file_get_contents($this->tempFile))); ServiceProvider::removeProviderFromBootstrapFile('App\Providers\TelescopeServiceProvider', $this->tempFile, true); - $this->assertSame(<<< PHP + $this->assertStringEqualsStringIgnoringLineEndings(<<< PHP tempFile); - $this->assertSame(<<< 'PHP' + $this->assertStringEqualsStringIgnoringLineEndings(<<< 'PHP' Date: Mon, 22 Sep 2025 17:24:30 -0400 Subject: [PATCH 3/8] style --- tests/Support/SupportServiceProviderTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Support/SupportServiceProviderTest.php b/tests/Support/SupportServiceProviderTest.php index 4d37b3d73adf..1c497dcc1a36 100644 --- a/tests/Support/SupportServiceProviderTest.php +++ b/tests/Support/SupportServiceProviderTest.php @@ -31,14 +31,12 @@ protected function setUp(): void $one->boot(); $two = new ServiceProviderForTestingTwo($app); $two->boot(); - - $this->tempFile = __DIR__ . '/providers.php'; } protected function tearDown(): void { m::close(); - if ($this->tempFile && file_exists($this->tempFile)) { + if (isset($this->tempFile) && file_exists($this->tempFile)) { @unlink($this->tempFile); } } @@ -200,7 +198,7 @@ public function testLoadTranslationsFromWithNamespace() public function test_can_remove_provider() { - + $this->tempFile = __DIR__.'/providers.php'; file_put_contents($this->tempFile, $contents = <<< PHP tempFile, true); // Should have deleted nothing $this->assertStringEqualsStringIgnoringLineEndings($contents, trim(file_get_contents($this->tempFile))); + // Should delete the telescope provider ServiceProvider::removeProviderFromBootstrapFile('App\Providers\TelescopeServiceProvider', $this->tempFile, true); $this->assertStringEqualsStringIgnoringLineEndings(<<< PHP @@ -226,6 +225,7 @@ public function test_can_remove_provider() PHP , trim(file_get_contents($this->tempFile))); + // Should fuzzily delete the App\Providers\AppServiceProvider class ServiceProvider::removeProviderFromBootstrapFile('AppServiceProvider', $this->tempFile); $this->assertStringEqualsStringIgnoringLineEndings(<<< 'PHP' From 53b0c2694f53d9c4c98b3204a9572b5ce782639c Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Wed, 24 Sep 2025 20:45:10 -0400 Subject: [PATCH 4/8] prePackageUninstall method --- src/Illuminate/Foundation/ComposerScripts.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Illuminate/Foundation/ComposerScripts.php b/src/Illuminate/Foundation/ComposerScripts.php index 8cf568409138..6ecd8dc614f1 100644 --- a/src/Illuminate/Foundation/ComposerScripts.php +++ b/src/Illuminate/Foundation/ComposerScripts.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation; +use Composer\Installer\PackageEvent; use Composer\Script\Event; class ComposerScripts @@ -45,6 +46,40 @@ public static function postAutoloadDump(Event $event) static::clearCompiled(); } + /** + * Handle the pre-package-uninstall Composer event. + * + * @param \Composer\Installer\PackageEvent $event + * @return void + */ + public static function prePackageUninstall(PackageEvent $event) + { + $bootstrapFile = $event->getComposer()->getConfig()->get('base-dir'); + + $bootstrapFile = dirname($vendorDir = $event->getComposer()->getConfig()->get('vendor-dir')).'/bootstrap/app.php'; + + if (! file_exists($bootstrapFile)) { + return; + } + + require_once $vendorDir.'/autoload.php'; + + define('LARAVEL_START', microtime(true)); + + /** @var Application $app */ + $app = require_once $bootstrapFile; + + /** @var \Composer\DependencyResolver\Operation\UninstallOperation $uninstallOperation */ + $uninstallOperation = $event->getOperation()->getPackage(); + $packageName = $uninstallOperation->getName(); + $isDev = $uninstallOperation->isDev(); + + $app['events']->dispatch('composer_package:uninstall:'.$packageName, [ + 'package' => $packageName, + 'isDev' => $isDev, + ]); + } + /** * Clear the cached Laravel bootstrapping files. * From 31102e33c330ad04292a01b670644435d89b070b Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Wed, 24 Sep 2025 20:48:49 -0400 Subject: [PATCH 5/8] rename event --- src/Illuminate/Foundation/ComposerScripts.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/ComposerScripts.php b/src/Illuminate/Foundation/ComposerScripts.php index 6ecd8dc614f1..6945787f1820 100644 --- a/src/Illuminate/Foundation/ComposerScripts.php +++ b/src/Illuminate/Foundation/ComposerScripts.php @@ -74,7 +74,7 @@ public static function prePackageUninstall(PackageEvent $event) $packageName = $uninstallOperation->getName(); $isDev = $uninstallOperation->isDev(); - $app['events']->dispatch('composer_package:uninstall:'.$packageName, [ + $app['events']->dispatch('composer_package:'.$packageName.':uninstall', [ 'package' => $packageName, 'isDev' => $isDev, ]); From 27216bf207a234bb61c9079457c6309a0e1a9653 Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Wed, 24 Sep 2025 20:52:51 -0400 Subject: [PATCH 6/8] rename event --- src/Illuminate/Foundation/ComposerScripts.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/ComposerScripts.php b/src/Illuminate/Foundation/ComposerScripts.php index 6945787f1820..fad649151e1d 100644 --- a/src/Illuminate/Foundation/ComposerScripts.php +++ b/src/Illuminate/Foundation/ComposerScripts.php @@ -74,7 +74,7 @@ public static function prePackageUninstall(PackageEvent $event) $packageName = $uninstallOperation->getName(); $isDev = $uninstallOperation->isDev(); - $app['events']->dispatch('composer_package:'.$packageName.':uninstall', [ + $app['events']->dispatch('composer_package:'.$packageName.':pre_uninstall', [ 'package' => $packageName, 'isDev' => $isDev, ]); From 66d42d58a98000e067343686c6e69a496d10b97b Mon Sep 17 00:00:00 2001 From: Luke Kuzmish Date: Thu, 25 Sep 2025 17:16:35 -0400 Subject: [PATCH 7/8] hey this works --- src/Illuminate/Foundation/ComposerScripts.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Foundation/ComposerScripts.php b/src/Illuminate/Foundation/ComposerScripts.php index fad649151e1d..7ace678388fd 100644 --- a/src/Illuminate/Foundation/ComposerScripts.php +++ b/src/Illuminate/Foundation/ComposerScripts.php @@ -4,6 +4,7 @@ use Composer\Installer\PackageEvent; use Composer\Script\Event; +use Illuminate\Contracts\Console\Kernel; class ComposerScripts { @@ -54,8 +55,6 @@ public static function postAutoloadDump(Event $event) */ public static function prePackageUninstall(PackageEvent $event) { - $bootstrapFile = $event->getComposer()->getConfig()->get('base-dir'); - $bootstrapFile = dirname($vendorDir = $event->getComposer()->getConfig()->get('vendor-dir')).'/bootstrap/app.php'; if (! file_exists($bootstrapFile)) { @@ -69,17 +68,16 @@ public static function prePackageUninstall(PackageEvent $event) /** @var Application $app */ $app = require_once $bootstrapFile; + $app->make(Kernel::class)->bootstrap(); + /** @var \Composer\DependencyResolver\Operation\UninstallOperation $uninstallOperation */ $uninstallOperation = $event->getOperation()->getPackage(); $packageName = $uninstallOperation->getName(); - $isDev = $uninstallOperation->isDev(); - $app['events']->dispatch('composer_package:'.$packageName.':pre_uninstall', [ - 'package' => $packageName, - 'isDev' => $isDev, - ]); + $app['events']->dispatch('composer_package.'.$packageName.':pre_uninstall'); } + /** * Clear the cached Laravel bootstrapping files. * From 1cc68d10309b8841ad12d826973c022140c9f20b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 29 Sep 2025 11:05:26 +0100 Subject: [PATCH 8/8] formatting --- src/Illuminate/Foundation/ComposerScripts.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/ComposerScripts.php b/src/Illuminate/Foundation/ComposerScripts.php index 7ace678388fd..8a8b16d96479 100644 --- a/src/Illuminate/Foundation/ComposerScripts.php +++ b/src/Illuminate/Foundation/ComposerScripts.php @@ -72,9 +72,8 @@ public static function prePackageUninstall(PackageEvent $event) /** @var \Composer\DependencyResolver\Operation\UninstallOperation $uninstallOperation */ $uninstallOperation = $event->getOperation()->getPackage(); - $packageName = $uninstallOperation->getName(); - $app['events']->dispatch('composer_package.'.$packageName.':pre_uninstall'); + $app['events']->dispatch('composer_package.'.$uninstallOperation->getName().':pre_uninstall'); }