Skip to content

Commit 51ff2a3

Browse files
[12.x] Dispatch framework events on composer pre-package-uninstall event (#57144)
* remove provider * string equals string ignoring line endings * style * prePackageUninstall method * rename event * rename event * hey this works * formatting --------- Co-authored-by: Taylor Otwell <[email protected]>
1 parent 0c88bb2 commit 51ff2a3

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

src/Illuminate/Foundation/ComposerScripts.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Illuminate\Foundation;
44

5+
use Composer\Installer\PackageEvent;
56
use Composer\Script\Event;
7+
use Illuminate\Contracts\Console\Kernel;
68

79
class ComposerScripts
810
{
@@ -45,6 +47,36 @@ public static function postAutoloadDump(Event $event)
4547
static::clearCompiled();
4648
}
4749

50+
/**
51+
* Handle the pre-package-uninstall Composer event.
52+
*
53+
* @param \Composer\Installer\PackageEvent $event
54+
* @return void
55+
*/
56+
public static function prePackageUninstall(PackageEvent $event)
57+
{
58+
$bootstrapFile = dirname($vendorDir = $event->getComposer()->getConfig()->get('vendor-dir')).'/bootstrap/app.php';
59+
60+
if (! file_exists($bootstrapFile)) {
61+
return;
62+
}
63+
64+
require_once $vendorDir.'/autoload.php';
65+
66+
define('LARAVEL_START', microtime(true));
67+
68+
/** @var Application $app */
69+
$app = require_once $bootstrapFile;
70+
71+
$app->make(Kernel::class)->bootstrap();
72+
73+
/** @var \Composer\DependencyResolver\Operation\UninstallOperation $uninstallOperation */
74+
$uninstallOperation = $event->getOperation()->getPackage();
75+
76+
$app['events']->dispatch('composer_package.'.$uninstallOperation->getName().':pre_uninstall');
77+
}
78+
79+
4880
/**
4981
* Clear the cached Laravel bootstrapping files.
5082
*

src/Illuminate/Support/ServiceProvider.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,51 @@ public static function addProviderToBootstrapFile(string $provider, ?string $pat
572572

573573
$content = '<?php
574574
575+
return [
576+
'.$providers.'
577+
];';
578+
579+
file_put_contents($path, $content.PHP_EOL);
580+
581+
return true;
582+
}
583+
584+
/**
585+
* Remove a provider from the application's provider bootstrap file.
586+
*
587+
* @param string|array $providersToRemove
588+
* @param string|null $path
589+
* @param bool $strict
590+
* @return bool
591+
*/
592+
public static function removeProviderFromBootstrapFile(string|array $providersToRemove, ?string $path = null, bool $strict = false)
593+
{
594+
$path ??= app()->getBootstrapProvidersPath();
595+
596+
if (! file_exists($path)) {
597+
return false;
598+
}
599+
600+
if (function_exists('opcache_invalidate')) {
601+
opcache_invalidate($path, true);
602+
}
603+
604+
$providersToRemove = Arr::wrap($providersToRemove);
605+
606+
$providers = (new Collection(require $path))
607+
->unique()
608+
->sort()
609+
->values()
610+
->when(
611+
$strict,
612+
static fn (Collection $providerCollection) => $providerCollection->reject(fn (string $p) => in_array($p, $providersToRemove, true)),
613+
static fn (Collection $providerCollection) => $providerCollection->reject(fn (string $p) => Str::contains($p, $providersToRemove))
614+
)
615+
->map(fn ($p) => ' '.$p.'::class,')
616+
->implode(PHP_EOL);
617+
618+
$content = '<?php
619+
575620
return [
576621
'.$providers.'
577622
];';

tests/Support/SupportServiceProviderTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
class SupportServiceProviderTest extends TestCase
1313
{
1414
protected $app;
15+
protected string $tempFile;
1516

1617
protected function setUp(): void
1718
{
@@ -35,6 +36,9 @@ protected function setUp(): void
3536
protected function tearDown(): void
3637
{
3738
m::close();
39+
if (isset($this->tempFile) && file_exists($this->tempFile)) {
40+
@unlink($this->tempFile);
41+
}
3842
}
3943

4044
public function testPublishableServiceProviders()
@@ -191,6 +195,48 @@ public function testLoadTranslationsFromWithNamespace()
191195
$provider = new ServiceProviderForTestingOne($this->app);
192196
$provider->loadTranslationsFrom(__DIR__.'/translations', 'namespace');
193197
}
198+
199+
public function test_can_remove_provider()
200+
{
201+
$this->tempFile = __DIR__.'/providers.php';
202+
file_put_contents($this->tempFile, $contents = <<< PHP
203+
<?php
204+
205+
return [
206+
App\Providers\AppServiceProvider::class,
207+
App\Providers\TelescopeServiceProvider::class,
208+
];
209+
PHP
210+
);
211+
ServiceProvider::removeProviderFromBootstrapFile('TelescopeServiceProvider', $this->tempFile, true);
212+
213+
// Should have deleted nothing
214+
$this->assertStringEqualsStringIgnoringLineEndings($contents, trim(file_get_contents($this->tempFile)));
215+
216+
// Should delete the telescope provider
217+
ServiceProvider::removeProviderFromBootstrapFile('App\Providers\TelescopeServiceProvider', $this->tempFile, true);
218+
219+
$this->assertStringEqualsStringIgnoringLineEndings(<<< PHP
220+
<?php
221+
222+
return [
223+
App\Providers\AppServiceProvider::class,
224+
];
225+
PHP
226+
, trim(file_get_contents($this->tempFile)));
227+
228+
// Should fuzzily delete the App\Providers\AppServiceProvider class
229+
ServiceProvider::removeProviderFromBootstrapFile('AppServiceProvider', $this->tempFile);
230+
231+
$this->assertStringEqualsStringIgnoringLineEndings(<<< 'PHP'
232+
<?php
233+
234+
return [
235+
236+
];
237+
PHP
238+
, trim(file_get_contents($this->tempFile)));
239+
}
194240
}
195241

196242
class ServiceProviderForTestingOne extends ServiceProvider

0 commit comments

Comments
 (0)