diff --git a/composer.json b/composer.json index 75c9b3f641..f8c596dfaa 100644 --- a/composer.json +++ b/composer.json @@ -110,6 +110,7 @@ "flarum/suspend": "self.version", "flarum/tags": "self.version", "flarum/messages": "self.version", + "flarum/composer-plugin": "self.version", "flarum/phpstan": "self.version", "flarum/testing": "self.version" }, @@ -122,6 +123,7 @@ "doctrine/dbal": "^3.6.2", "dragonmantank/cron-expression": "^3.3", "fakerphp/faker": "^1.9.1", + "flarum/composer-plugin": "2.x-dev", "flarum/json-api-server": "^0.1.0", "franzl/whoops-middleware": "2.0", "guzzlehttp/guzzle": "*", diff --git a/extensions/package-manager/src/ExtensionManagerServiceProvider.php b/extensions/package-manager/src/ExtensionManagerServiceProvider.php index d40b0e1828..2c819df632 100755 --- a/extensions/package-manager/src/ExtensionManagerServiceProvider.php +++ b/extensions/package-manager/src/ExtensionManagerServiceProvider.php @@ -15,8 +15,11 @@ use Flarum\Extension\ExtensionManager; use Flarum\ExtensionManager\Composer\ComposerAdapter; use Flarum\ExtensionManager\Event\FlarumUpdated; +use Flarum\ExtensionManager\Extension\Event\Installed; +use Flarum\ExtensionManager\Extension\Event\Removed; use Flarum\ExtensionManager\Extension\Event\Updated; use Flarum\ExtensionManager\Listener\ClearCacheAfterUpdate; +use Flarum\ExtensionManager\Listener\ClearOPCacheAfterUpdate; use Flarum\ExtensionManager\Listener\ReCheckForUpdates; use Flarum\Foundation\AbstractServiceProvider; use Flarum\Foundation\Paths; @@ -100,5 +103,6 @@ function (Updated $event) use ($container) { $events->listen(FlarumUpdated::class, ClearCacheAfterUpdate::class); $events->listen([FlarumUpdated::class, Updated::class], ReCheckForUpdates::class); + $events->listen([Installed::class, Updated::class, Removed::class, FlarumUpdated::class], ClearOPCacheAfterUpdate::class); } } diff --git a/extensions/package-manager/src/Listener/ClearOPCacheAfterUpdate.php b/extensions/package-manager/src/Listener/ClearOPCacheAfterUpdate.php new file mode 100644 index 0000000000..d2551ebc22 --- /dev/null +++ b/extensions/package-manager/src/Listener/ClearOPCacheAfterUpdate.php @@ -0,0 +1,26 @@ +paths->storage . ClearOPCache::PATH; + + if (file_exists($path) || ! function_exists('opcache_reset')) { + return; + } + + @file_put_contents($path, (string) time()); + } +} diff --git a/framework/core/composer.json b/framework/core/composer.json index a2b5bfdb78..9ada459b04 100644 --- a/framework/core/composer.json +++ b/framework/core/composer.json @@ -42,6 +42,7 @@ "doctrine/dbal": "^3.6", "dragonmantank/cron-expression": "*", "fakerphp/faker": "^1.9.1", + "flarum/composer-plugin": "2.x-dev", "franzl/whoops-middleware": "2.0", "guzzlehttp/guzzle": "^7.7", "illuminate/bus": "^13.0", diff --git a/framework/core/src/Admin/AdminServiceProvider.php b/framework/core/src/Admin/AdminServiceProvider.php index f8bc098eef..631d09188b 100644 --- a/framework/core/src/Admin/AdminServiceProvider.php +++ b/framework/core/src/Admin/AdminServiceProvider.php @@ -50,6 +50,7 @@ public function register(): void $this->container->singleton('flarum.admin.middleware', function () { return [ + HttpMiddleware\ClearOPCache::class, HttpMiddleware\InjectActorReference::class, 'flarum.admin.error_handler', HttpMiddleware\ParseJsonBody::class, diff --git a/framework/core/src/Api/ApiServiceProvider.php b/framework/core/src/Api/ApiServiceProvider.php index 3ea3cbbb9e..9d9b10d8cc 100644 --- a/framework/core/src/Api/ApiServiceProvider.php +++ b/framework/core/src/Api/ApiServiceProvider.php @@ -86,6 +86,7 @@ public function register(): void $this->container->singleton('flarum.api.middleware', function () { return [ + HttpMiddleware\ClearOPCache::class, HttpMiddleware\InjectActorReference::class, 'flarum.api.error_handler', HttpMiddleware\ParseJsonBody::class, diff --git a/framework/core/src/Forum/ForumServiceProvider.php b/framework/core/src/Forum/ForumServiceProvider.php index 963b28012e..592273fbc8 100644 --- a/framework/core/src/Forum/ForumServiceProvider.php +++ b/framework/core/src/Forum/ForumServiceProvider.php @@ -61,6 +61,7 @@ public function register(): void $this->container->singleton('flarum.forum.middleware', function () { return [ + HttpMiddleware\ClearOPCache::class, HttpMiddleware\InjectActorReference::class, 'flarum.forum.error_handler', HttpMiddleware\ParseJsonBody::class, diff --git a/framework/core/src/Http/Middleware/ClearOPCache.php b/framework/core/src/Http/Middleware/ClearOPCache.php new file mode 100644 index 0000000000..2f4d88fd3c --- /dev/null +++ b/framework/core/src/Http/Middleware/ClearOPCache.php @@ -0,0 +1,55 @@ +path())) { + return $handler->handle($request); + } + + opcache_reset(); + + @unlink($this->path()); + + return $handler->handle($request); + } + + public function path(): string + { + if ($this->container->bound(Paths::class)) { + return $this->container->make(Paths::class)->storage . static::PATH; + } + + // Fallback when Paths is not available during installation. + $path = dirname(__DIR__, 3); + $upTo = dirname(__DIR__, 6); + + while(true) { + if ($path === $upTo) throw new Exception('Could not find storage directory'); + if ($path === '.') throw new Exception('Could not find storage directory'); + + if (is_dir("$path/storage")) break; + $path = dirname($path); + } + + return "$path/storage" . static::PATH; + } +} diff --git a/framework/core/src/Install/Installer.php b/framework/core/src/Install/Installer.php index 192e499cd5..9cce790bf6 100644 --- a/framework/core/src/Install/Installer.php +++ b/framework/core/src/Install/Installer.php @@ -34,6 +34,7 @@ public function getContainer(): Container public function getRequestHandler(): RequestHandlerInterface { $pipe = new MiddlewarePipe; + $pipe->pipe(new HttpMiddleware\ClearOPCache($this->getContainer())); $pipe->pipe(new HttpMiddleware\HandleErrors( $this->container->make(Registry::class), $this->container->make(WhoopsFormatter::class), diff --git a/php-packages/composer-plugin/composer.json b/php-packages/composer-plugin/composer.json new file mode 100644 index 0000000000..231f70611a --- /dev/null +++ b/php-packages/composer-plugin/composer.json @@ -0,0 +1,23 @@ +{ + "name": "flarum/composer-plugin", + "description": "Assists Flarum with Composer", + "type": "composer-plugin", + "license": "MIT", + "require": { + "composer-plugin-api": "^2.0" + }, + "require-dev": { + "composer/composer": "^2.0" + }, + "autoload": { + "psr-4": { + "Flarum\\Composer\\Plugin\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + }, + "class": "Flarum\\Composer\\Plugin\\ComposerPlugin" + } +} diff --git a/php-packages/composer-plugin/src/ComposerPlugin.php b/php-packages/composer-plugin/src/ComposerPlugin.php new file mode 100644 index 0000000000..4a90558c47 --- /dev/null +++ b/php-packages/composer-plugin/src/ComposerPlugin.php @@ -0,0 +1,44 @@ +composer = $composer; + } + + public function deactivate(Composer $composer, IOInterface $io): void {} + public function uninstall(Composer $composer, IOInterface $io): void {} + + + public static function getSubscribedEvents(): array + { + return [ + 'post-autoload-dump' => 'flag', + ]; + } + + public function flag(): void + { + $path = class_exists(ClearOPCache::class) ? ClearOPCache::PATH : '/storage/cache/clear-opcache'; + + $vendorDir = $this->composer->getConfig()->get('vendor-dir'); + $flagFile = dirname($vendorDir) . $path; + + if (is_dir(dirname($flagFile)) && ! file_exists($flagFile)) { + @file_put_contents($flagFile, (string) time()); + } + } +}