diff --git a/framework/core/src/Admin/AdminServiceProvider.php b/framework/core/src/Admin/AdminServiceProvider.php
index 4f815fcef..496e819c7 100644
--- a/framework/core/src/Admin/AdminServiceProvider.php
+++ b/framework/core/src/Admin/AdminServiceProvider.php
@@ -28,27 +28,12 @@ use Flarum\Http\RouteHandlerFactory;
use Flarum\Locale\LocaleManager;
use Flarum\Settings\Event\Saved;
use Illuminate\Contracts\Container\Container;
+use Illuminate\Contracts\Events\Dispatcher;
class AdminServiceProvider extends AbstractServiceProvider
{
public function register(): void
{
- $this->booted(function (Container $container) {
- /** @var Router $router */
- $router = $container->make(Router::class);
- /** @var Config $config */
- $config = $container->make(Config::class);
-
- $router->middlewareGroup('admin', $container->make('flarum.admin.middleware'));
-
- $factory = $container->make(RouteHandlerFactory::class);
-
- $router->middleware('admin')
- ->prefix($config->path('admin'))
- ->name('admin.')
- ->group(fn (Router $router) => (include __DIR__.'/routes.php')($router, $factory));
- });
-
$this->container->singleton('flarum.admin.middleware', function () {
return [
HttpMiddleware\InjectActorReference::class,
@@ -101,18 +86,17 @@ class AdminServiceProvider extends AbstractServiceProvider
});
}
- public function boot(): void
+ public function boot(Container $container, Dispatcher $events): void
{
+ $this->addRoutes($container);
$this->loadViewsFrom(__DIR__.'/../../views', 'flarum.admin');
- $events = $this->container->make('events');
-
$events->listen(
[Enabled::class, Disabled::class, ClearingCache::class],
- function () {
+ function () use ($container) {
$recompile = new RecompileFrontendAssets(
- $this->container->make('flarum.assets.admin'),
- $this->container->make(LocaleManager::class)
+ $container->make('flarum.assets.admin'),
+ $container->make(LocaleManager::class)
);
$recompile->flush();
}
@@ -120,13 +104,30 @@ class AdminServiceProvider extends AbstractServiceProvider
$events->listen(
Saved::class,
- function (Saved $event) {
+ function (Saved $event) use ($container) {
$recompile = new RecompileFrontendAssets(
- $this->container->make('flarum.assets.admin'),
- $this->container->make(LocaleManager::class)
+ $container->make('flarum.assets.admin'),
+ $container->make(LocaleManager::class)
);
$recompile->whenSettingsSaved($event);
}
);
}
+
+ protected function addRoutes(Container $container)
+ {
+ /** @var Router $router */
+ $router = $container->make(Router::class);
+ /** @var Config $config */
+ $config = $container->make(Config::class);
+
+ $router->middlewareGroup('admin', $container->make('flarum.admin.middleware'));
+
+ $factory = $container->make(RouteHandlerFactory::class);
+
+ $router->middleware('admin')
+ ->prefix($config->path('admin'))
+ ->name('admin.')
+ ->group(fn (Router $router) => (include __DIR__.'/routes.php')($router, $factory));
+ }
}
diff --git a/framework/core/src/Api/ApiServiceProvider.php b/framework/core/src/Api/ApiServiceProvider.php
index 49b64f7c7..89d2ea597 100644
--- a/framework/core/src/Api/ApiServiceProvider.php
+++ b/framework/core/src/Api/ApiServiceProvider.php
@@ -19,31 +19,19 @@ use Flarum\Foundation\ErrorHandling\JsonApiFormatter;
use Flarum\Foundation\ErrorHandling\Registry;
use Flarum\Foundation\ErrorHandling\Reporter;
use Flarum\Http\Middleware as HttpMiddleware;
+use Flarum\Http\RouteHandlerFactory;
use Flarum\Http\Router;
use Illuminate\Contracts\Container\Container;
+use Illuminate\Http\Request;
class ApiServiceProvider extends AbstractServiceProvider
{
public function register(): void
{
- $this->booted(function (Container $container) {
- /** @var Router $router */
- $router = $container->make(Router::class);
- /** @var Config $config */
- $config = $container->make(Config::class);
-
- $router->middlewareGroup('api', $container->make('flarum.api.middleware'));
-
- $router->middleware('api')
- ->prefix($config->path('api'))
- ->name('api.')
- ->group(fn (Router $router) => (include __DIR__.'/routes.php')($router));
- });
-
$this->container->singleton('flarum.api.throttlers', function () {
return [
- 'bypassThrottlingAttribute' => function ($request) {
- if ($request->getAttribute('bypassThrottling')) {
+ 'bypassThrottlingAttribute' => function (Request $request) {
+ if ($request->attributes->get('bypassThrottling')) {
return false;
}
}
@@ -108,6 +96,7 @@ class ApiServiceProvider extends AbstractServiceProvider
public function boot(Container $container): void
{
+ $this->addRoutes($container);
$this->setNotificationSerializers();
AbstractSerializeController::setContainer($container);
@@ -123,4 +112,21 @@ class ApiServiceProvider extends AbstractServiceProvider
NotificationSerializer::setSubjectSerializer($type, $serializer);
}
}
+
+ protected function addRoutes(Container $container)
+ {
+ /** @var Router $router */
+ $router = $container->make(Router::class);
+ /** @var Config $config */
+ $config = $container->make(Config::class);
+
+ $router->middlewareGroup('api', $container->make('flarum.api.middleware'));
+
+ $factory = $container->make(RouteHandlerFactory::class);
+
+ $router->middleware('api')
+ ->prefix($config->path('api'))
+ ->name('api.')
+ ->group(fn (Router $router) => (include __DIR__.'/routes.php')($router, $factory));
+ }
}
diff --git a/framework/core/src/Database/DatabaseServiceProvider.php b/framework/core/src/Database/DatabaseServiceProvider.php
index dfae3d6ac..cdb918043 100644
--- a/framework/core/src/Database/DatabaseServiceProvider.php
+++ b/framework/core/src/Database/DatabaseServiceProvider.php
@@ -13,7 +13,6 @@ use Flarum\Foundation\AbstractServiceProvider;
use Illuminate\Container\Container as ContainerImplementation;
use Illuminate\Contracts\Container\Container;
use Illuminate\Database\Capsule\Manager;
-use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\ConnectionResolverInterface;
class DatabaseServiceProvider extends AbstractServiceProvider
@@ -32,7 +31,8 @@ class DatabaseServiceProvider extends AbstractServiceProvider
return $manager;
});
- $this->container->singleton(ConnectionResolverInterface::class, function (Container $container) {
+ $this->container->singleton('db', function (Container $container) {
+ /** @var Manager $manager */
$manager = $container->make(Manager::class);
$manager->setAsGlobal();
$manager->bootEloquent();
@@ -43,19 +43,15 @@ class DatabaseServiceProvider extends AbstractServiceProvider
return $dbManager;
});
- $this->container->alias(ConnectionResolverInterface::class, 'db');
-
- $this->container->singleton(ConnectionInterface::class, function (Container $container) {
- $resolver = $container->make(ConnectionResolverInterface::class);
+ $this->container->singleton('db.connection', function (Container $container) {
+ /** @var ConnectionResolverInterface $resolver */
+ $resolver = $container->make('db');
return $resolver->connection();
});
- $this->container->alias(ConnectionInterface::class, 'db.connection');
- $this->container->alias(ConnectionInterface::class, 'flarum.db');
-
$this->container->singleton(MigrationRepositoryInterface::class, function (Container $container) {
- return new DatabaseMigrationRepository($container['flarum.db'], 'migrations');
+ return new DatabaseMigrationRepository($container['db.connection'], 'migrations');
});
$this->container->singleton('flarum.database.model_private_checkers', function () {
diff --git a/framework/core/src/Extend/Concerns/ExtendsRoutes.php b/framework/core/src/Extend/Concerns/ExtendsRoutes.php
index 7f56de06f..b1c4f90da 100644
--- a/framework/core/src/Extend/Concerns/ExtendsRoutes.php
+++ b/framework/core/src/Extend/Concerns/ExtendsRoutes.php
@@ -26,6 +26,7 @@ trait ExtendsRoutes
/** @var Router $router */
$router = $container->make(Router::class);
/** @var Config $config */
+ $config = $container->make(Config::class);
foreach ($this->removedRoutes as $routeName) {
$router->forgetRoute($routeName);
diff --git a/framework/core/src/Extend/ThrottleApi.php b/framework/core/src/Extend/ThrottleApi.php
index afb3a05a0..37d381e3e 100644
--- a/framework/core/src/Extend/ThrottleApi.php
+++ b/framework/core/src/Extend/ThrottleApi.php
@@ -28,7 +28,7 @@ class ThrottleApi implements ExtenderInterface
* The callable can be a closure or invokable class, and should accept:
* - $request: The current `\Illuminate\Http\Request` request object.
* `\Flarum\Http\RequestUtil::getActor($request)` can be used to get the current user.
- * `$request->getAttribute('routeName')` can be used to get the current route.
+ * `$request->attributes->get('routeName')` can be used to get the current route.
* Please note that every throttler runs by default on every route.
* If you only want to throttle certain routes, you'll need to check for that inside your logic.
*
diff --git a/framework/core/src/Forum/Content/Discussion.php b/framework/core/src/Forum/Content/Discussion.php
index c7b3f5bc7..f78b03440 100644
--- a/framework/core/src/Forum/Content/Discussion.php
+++ b/framework/core/src/Forum/Content/Discussion.php
@@ -104,6 +104,6 @@ class Discussion
throw new RouteNotFoundException;
}
- return json_decode($response->getBody());
+ return $response->getData();
}
}
diff --git a/framework/core/src/Forum/Content/Index.php b/framework/core/src/Forum/Content/Index.php
index b8fa268d0..e2a2bbf96 100644
--- a/framework/core/src/Forum/Content/Index.php
+++ b/framework/core/src/Forum/Content/Index.php
@@ -54,7 +54,7 @@ class Index
$document->content = $this->view->make('flarum.forum::frontend.content.index', compact('apiDocument', 'page'));
$document->payload['apiDocument'] = $apiDocument;
- $document->canonicalUrl = $this->url->base('forum').($defaultRoute === '/all' ? '' : $request->getUri()->getPath());
+ $document->canonicalUrl = $this->url->base('forum').($defaultRoute === '/all' ? '' : $request->getUri());
$document->page = $page;
$document->hasNextPage = isset($apiDocument->links->next);
@@ -66,6 +66,6 @@ class Index
*/
protected function getApiDocument(Request $request, array $params): object
{
- return json_decode($this->api->withParentRequest($request)->withQueryParams($params)->get('/discussions')->getBody());
+ return $this->api->withParentRequest($request)->withQueryParams($params)->get('/discussions')->getData();
}
}
diff --git a/framework/core/src/Forum/Controller/LogInController.php b/framework/core/src/Forum/Controller/LogInController.php
index 4a7e1a402..5ecb6858e 100644
--- a/framework/core/src/Forum/Controller/LogInController.php
+++ b/framework/core/src/Forum/Controller/LogInController.php
@@ -45,7 +45,7 @@ class LogInController extends AbstractController
$response = $this->apiClient->withParentRequest($request)->withBody($params)->post('/token');
if ($response->getStatusCode() === 200) {
- $data = json_decode($response->getBody());
+ $data = $response->getData();
$token = AccessToken::findValid($data->token);
diff --git a/framework/core/src/Forum/Controller/RegisterController.php b/framework/core/src/Forum/Controller/RegisterController.php
index 29a4909c9..4da8ead07 100644
--- a/framework/core/src/Forum/Controller/RegisterController.php
+++ b/framework/core/src/Forum/Controller/RegisterController.php
@@ -32,7 +32,7 @@ class RegisterController extends AbstractController
$response = $this->api->withParentRequest($request)->withBody($params)->post('/users');
- $body = json_decode($response->getBody());
+ $body = $response->getData();
if (isset($body->data)) {
$userId = $body->data->id;
diff --git a/framework/core/src/Forum/ForumServiceProvider.php b/framework/core/src/Forum/ForumServiceProvider.php
index 96199322d..3785dcac0 100644
--- a/framework/core/src/Forum/ForumServiceProvider.php
+++ b/framework/core/src/Forum/ForumServiceProvider.php
@@ -34,33 +34,13 @@ use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\View\Factory;
+use Illuminate\Support\Arr;
use Symfony\Contracts\Translation\TranslatorInterface;
class ForumServiceProvider extends AbstractServiceProvider
{
public function register(): void
{
- $this->booted(function (Container $container) {
- /** @var Router $router */
- $router = $container->make(Router::class);
- /** @var Config $config */
- $config = $container->make(Config::class);
-
- $router->middlewareGroup('forum', $container->make('flarum.forum.middleware'));
-
- $factory = $container->make(RouteHandlerFactory::class);
-
- $router->middleware('forum')
- ->prefix($config->path('forum'))
- ->name('forum.')
- ->group(fn (Router $router) => (include __DIR__.'/routes.php')($router, $factory));
-
- $this->setDefaultRoute(
- $router,
- $container->make(SettingsRepositoryInterface::class)
- );
- });
-
$this->container->singleton('flarum.forum.middleware', function () {
return [
HttpMiddleware\InjectActorReference::class,
@@ -130,6 +110,7 @@ class ForumServiceProvider extends AbstractServiceProvider
public function boot(Container $container, Dispatcher $events, Factory $view): void
{
+ $this->addRoutes($container);
$this->loadViewsFrom(__DIR__.'/../../views', 'flarum.forum');
$view->share([
@@ -181,10 +162,33 @@ class ForumServiceProvider extends AbstractServiceProvider
);
}
+ protected function addRoutes(Container $container): void
+ {
+ /** @var Router $router */
+ $router = $container->make(Router::class);
+ /** @var Config $config */
+ $config = $container->make(Config::class);
+
+ $router->middlewareGroup('forum', $container->make('flarum.forum.middleware'));
+
+ $factory = $container->make(RouteHandlerFactory::class);
+
+ $router->middleware('forum')
+ ->prefix($config->path('forum'))
+ ->name('forum.')
+ ->group(fn (Router $router) => (include __DIR__.'/routes.php')($router, $factory));
+
+ $this->setDefaultRoute(
+ $router,
+ $container->make(SettingsRepositoryInterface::class)
+ );
+ }
+
protected function setDefaultRoute(Router $router, SettingsRepositoryInterface $settings): void
{
- $defaultRoute = $settings->get('default_route');
- $action = $router->getRoutes()->getByName($defaultRoute)?->getAction() ?? 'index';
- $router->get('/', $action)->name('default');
+ $defaultRoutePath = ltrim($settings->get('default_route', '/all'), '/');
+ /** @var \Illuminate\Routing\Route $route */
+ $route = $router->getRoutes()->getRoutesByMethod()['GET'][$defaultRoutePath];
+ $router->get('/', Arr::except($route->getAction(), ['as']))->name('forum.default');
}
}
diff --git a/framework/core/src/Foundation/Application.php b/framework/core/src/Foundation/Application.php
index 42b418bf7..682aa42b5 100644
--- a/framework/core/src/Foundation/Application.php
+++ b/framework/core/src/Foundation/Application.php
@@ -9,8 +9,10 @@
namespace Flarum\Foundation;
+use Flarum\Database\DatabaseServiceProvider;
use Flarum\Foundation\Concerns\InteractsWithLaravel;
use Flarum\Http\RoutingServiceProvider;
+use Flarum\Settings\SettingsServiceProvider;
use Illuminate\Container\Container as IlluminateContainer;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Foundation\Application as LaravelApplication;
@@ -39,6 +41,8 @@ class Application extends IlluminateContainer implements LaravelApplication
protected array $loadedProviders = [];
+ protected bool $hasBeenBootstrapped = false;
+
public function __construct(
protected Paths $paths
) {
@@ -80,6 +84,13 @@ class Application extends IlluminateContainer implements LaravelApplication
{
$this->register(new EventServiceProvider($this));
$this->register(new RoutingServiceProvider($this));
+
+ // Because we need to check very early if the version of the app
+ // in the settings table matches the current version, we need
+ // to register the settings provider and therefore the database
+ // provider very early on.
+ $this->register(new DatabaseServiceProvider($this));
+ $this->register(new SettingsServiceProvider($this));
}
public function register($provider, $force = false): ServiceProvider
@@ -194,16 +205,35 @@ class Application extends IlluminateContainer implements LaravelApplication
}
}
+ public function bootstrapWith(array $bootstrappers): void
+ {
+ $this->hasBeenBootstrapped = true;
+
+ foreach ($bootstrappers as $bootstrapper) {
+ $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);
+
+ $this->make($bootstrapper)->bootstrap($this);
+
+ $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
+ }
+ }
+
+ public function hasBeenBootstrapped(): bool
+ {
+ return $this->hasBeenBootstrapped;
+ }
+
public function registerCoreContainerAliases(): void
{
$aliases = [
'app' => [\Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
'blade.compiler' => [\Illuminate\View\Compilers\BladeCompiler::class],
'cache' => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
+ 'cache.filestore' => [\Illuminate\Cache\FileStore::class, \Illuminate\Contracts\Cache\Store::class],
'cache.store' => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class],
'config' => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
'container' => [\Illuminate\Contracts\Container\Container::class, \Psr\Container\ContainerInterface::class],
- 'db' => [\Illuminate\Database\DatabaseManager::class],
+ 'db' => [\Illuminate\Database\ConnectionResolverInterface::class, \Illuminate\Database\DatabaseManager::class],
'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
'events' => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
'files' => [\Illuminate\Filesystem\Filesystem::class],
@@ -211,9 +241,12 @@ class Application extends IlluminateContainer implements LaravelApplication
'filesystem.disk' => [\Illuminate\Contracts\Filesystem\Filesystem::class],
'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class],
'flarum' => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
+ 'flarum.config' => [Config::class],
'flarum.paths' => [Paths::class],
+ 'flarum.settings' => [\Flarum\Settings\SettingsRepositoryInterface::class],
'hash' => [\Illuminate\Contracts\Hashing\Hasher::class],
'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
+ 'request' => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
'router' => [\Flarum\Http\Router::class, \Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
'session' => [\Illuminate\Session\SessionManager::class],
'session.store' => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class],
diff --git a/framework/core/src/Foundation/Bootstrap/BootProviders.php b/framework/core/src/Foundation/Bootstrap/BootProviders.php
new file mode 100644
index 000000000..94a002057
--- /dev/null
+++ b/framework/core/src/Foundation/Bootstrap/BootProviders.php
@@ -0,0 +1,15 @@
+boot();
+ }
+}
diff --git a/framework/core/src/Foundation/Bootstrap/IlluminateBootstrapperInterface.php b/framework/core/src/Foundation/Bootstrap/IlluminateBootstrapperInterface.php
new file mode 100644
index 000000000..e571a7435
--- /dev/null
+++ b/framework/core/src/Foundation/Bootstrap/IlluminateBootstrapperInterface.php
@@ -0,0 +1,10 @@
+register(ErrorServiceProvider::class);
+ $app->register(LocaleServiceProvider::class);
+ $app->register(FilesystemServiceProvider::class);
+ $app->register(SessionServiceProvider::class);
+ $app->register(ValidationServiceProvider::class);
+
+ $app->register(InstallServiceProvider::class);
+
+ $this->registerLogger($app);
+
+ $app->singleton(
+ SettingsRepositoryInterface::class,
+ UninstalledSettingsRepository::class
+ );
+
+ $app->singleton('view', function ($app) {
+ $engines = new EngineResolver();
+ $engines->register('php', function () use ($app) {
+ return $app->make(PhpEngine::class);
+ });
+ $finder = new FileViewFinder($app->make('files'), []);
+ $dispatcher = $app->make(Dispatcher::class);
+
+ return new \Illuminate\View\Factory(
+ $engines,
+ $finder,
+ $dispatcher
+ );
+ });
+ }
+
+ protected function registerLogger(Application $app): void
+ {
+ /** @var \Flarum\Foundation\Paths $paths */
+ $paths = $app['flarum.paths'];
+
+ $logPath = $paths->storage.'/logs/flarum-installer.log';
+ $handler = new StreamHandler($logPath, Level::Debug);
+ $handler->setFormatter(new LineFormatter(null, null, true, true));
+
+ $app->instance('log', new Logger('Flarum Installer', [$handler]));
+ $app->alias('log', LoggerInterface::class);
+ }
+}
diff --git a/framework/core/src/Foundation/Bootstrap/RegisterCache.php b/framework/core/src/Foundation/Bootstrap/RegisterCache.php
new file mode 100644
index 000000000..18bc4963c
--- /dev/null
+++ b/framework/core/src/Foundation/Bootstrap/RegisterCache.php
@@ -0,0 +1,25 @@
+singleton('cache.store', function ($app) {
+ return new CacheRepository($app->make('cache.filestore'));
+ });
+
+ $app->singleton('cache.filestore', function () use ($paths) {
+ return new FileStore(new Filesystem, $paths->storage.'/cache');
+ });
+ }
+}
diff --git a/framework/core/src/Foundation/Bootstrap/RegisterCoreProviders.php b/framework/core/src/Foundation/Bootstrap/RegisterCoreProviders.php
new file mode 100644
index 000000000..68310eed2
--- /dev/null
+++ b/framework/core/src/Foundation/Bootstrap/RegisterCoreProviders.php
@@ -0,0 +1,66 @@
+register(AdminServiceProvider::class);
+ $app->register(ApiServiceProvider::class);
+ $app->register(BusServiceProvider::class);
+ $app->register(ConsoleServiceProvider::class);
+ $app->register(DiscussionServiceProvider::class);
+ $app->register(ExtensionServiceProvider::class);
+ $app->register(ErrorServiceProvider::class);
+ $app->register(FilesystemServiceProvider::class);
+ $app->register(FilterServiceProvider::class);
+ $app->register(FormatterServiceProvider::class);
+ $app->register(ForumServiceProvider::class);
+ $app->register(FrontendServiceProvider::class);
+ $app->register(GroupServiceProvider::class);
+ $app->register(HashServiceProvider::class);
+ $app->register(HttpServiceProvider::class);
+ $app->register(LocaleServiceProvider::class);
+ $app->register(MailServiceProvider::class);
+ $app->register(NotificationServiceProvider::class);
+ $app->register(PostServiceProvider::class);
+ $app->register(QueueServiceProvider::class);
+ $app->register(SearchServiceProvider::class);
+ $app->register(SessionServiceProvider::class);
+ $app->register(UpdateServiceProvider::class);
+ $app->register(UserServiceProvider::class);
+ $app->register(ValidationServiceProvider::class);
+ $app->register(ViewServiceProvider::class);
+ }
+}
diff --git a/framework/core/src/Foundation/Bootstrap/RegisterLogger.php b/framework/core/src/Foundation/Bootstrap/RegisterLogger.php
new file mode 100644
index 000000000..2621202cc
--- /dev/null
+++ b/framework/core/src/Foundation/Bootstrap/RegisterLogger.php
@@ -0,0 +1,31 @@
+storage.'/logs/flarum.log';
+ $logLevel = $config->inDebugMode() ? Level::Debug : Level::Info;
+ $handler = new RotatingFileHandler($logPath, 0, $logLevel);
+ $handler->setFormatter(new LineFormatter(null, null, true, true));
+
+ $app->instance('log', new Logger('flarum', [$handler]));
+ $app->alias('log', LoggerInterface::class);
+ }
+}
diff --git a/framework/core/src/Foundation/Bootstrap/RegisterMaintenanceHandler.php b/framework/core/src/Foundation/Bootstrap/RegisterMaintenanceHandler.php
new file mode 100644
index 000000000..00c4534b7
--- /dev/null
+++ b/framework/core/src/Foundation/Bootstrap/RegisterMaintenanceHandler.php
@@ -0,0 +1,14 @@
+instance('flarum.maintenance.handler', new MaintenanceModeHandler);
+ }
+}
diff --git a/framework/core/src/Foundation/Concerns/InteractsWithLaravel.php b/framework/core/src/Foundation/Concerns/InteractsWithLaravel.php
index 30b833c4b..7f4e2b8b7 100644
--- a/framework/core/src/Foundation/Concerns/InteractsWithLaravel.php
+++ b/framework/core/src/Foundation/Concerns/InteractsWithLaravel.php
@@ -165,14 +165,6 @@ trait InteractsWithLaravel
//
}
- /**
- * @deprecated Not actually used/has no meaning in Flarum.
- */
- public function bootstrapWith(array $bootstrappers)
- {
- //
- }
-
public function getLocale()
{
return $this->make(LocaleManager::class)->getLocale();
@@ -190,14 +182,6 @@ trait InteractsWithLaravel
return Arr::where($this->serviceProviders, fn ($value) => $value instanceof $name);
}
- /**
- * @deprecated Not actually used/has no meaning in Flarum.
- */
- public function hasBeenBootstrapped()
- {
- //
- }
-
/**
* @deprecated Not actually used/has no meaning in Flarum.
*/
diff --git a/framework/core/src/Foundation/InstalledApp.php b/framework/core/src/Foundation/InstalledApp.php
index 6a12b3102..c4e432e8f 100644
--- a/framework/core/src/Foundation/InstalledApp.php
+++ b/framework/core/src/Foundation/InstalledApp.php
@@ -12,14 +12,11 @@ namespace Flarum\Foundation;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Console\Command;
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
-use Laminas\Stratigility\Middleware\OriginalMessages;
-use Middlewares\BasePath;
class InstalledApp implements AppInterface
{
public function __construct(
protected ApplicationContract $app,
- protected Config $config
) {
}
@@ -51,23 +48,17 @@ class InstalledApp implements AppInterface
protected function getUpdaterMiddlewareStack(): array
{
return [
- new BasePath($this->basePath()),
+ //
];
}
protected function getStandardMiddlewareStack(): array
{
return [
- new BasePath($this->basePath()),
- new OriginalMessages,
+ //
];
}
- protected function basePath(): string
- {
- return $this->config->url()->getPath() ?: '/';
- }
-
public function getConsoleCommands(): array
{
return array_map(function ($command) {
diff --git a/framework/core/src/Foundation/InstalledSite.php b/framework/core/src/Foundation/InstalledSite.php
index 9e205e06b..651266409 100644
--- a/framework/core/src/Foundation/InstalledSite.php
+++ b/framework/core/src/Foundation/InstalledSite.php
@@ -9,47 +9,9 @@
namespace Flarum\Foundation;
-use Flarum\Admin\AdminServiceProvider;
-use Flarum\Api\ApiServiceProvider;
-use Flarum\Bus\BusServiceProvider;
-use Flarum\Console\ConsoleServiceProvider;
-use Flarum\Database\DatabaseServiceProvider;
-use Flarum\Discussion\DiscussionServiceProvider;
use Flarum\Extend\ExtenderInterface;
-use Flarum\Extension\ExtensionServiceProvider;
-use Flarum\Filesystem\FilesystemServiceProvider;
-use Flarum\Filter\FilterServiceProvider;
-use Flarum\Formatter\FormatterServiceProvider;
-use Flarum\Forum\ForumServiceProvider;
-use Flarum\Frontend\FrontendServiceProvider;
-use Flarum\Group\GroupServiceProvider;
-use Flarum\Http\HttpServiceProvider;
-use Flarum\Locale\LocaleServiceProvider;
-use Flarum\Mail\MailServiceProvider;
-use Flarum\Notification\NotificationServiceProvider;
-use Flarum\Post\PostServiceProvider;
-use Flarum\Queue\QueueServiceProvider;
-use Flarum\Search\SearchServiceProvider;
-use Flarum\Settings\SettingsServiceProvider;
-use Flarum\Update\UpdateServiceProvider;
-use Flarum\User\SessionServiceProvider;
-use Flarum\User\UserServiceProvider;
-use Illuminate\Cache\FileStore;
-use Illuminate\Cache\Repository as CacheRepository;
use Illuminate\Config\Repository as ConfigRepository;
-use Illuminate\Contracts\Cache\Repository;
-use Illuminate\Contracts\Cache\Store;
-use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
-use Illuminate\Filesystem\Filesystem;
-use Illuminate\Hashing\HashServiceProvider;
-use Illuminate\Validation\ValidationServiceProvider;
-use Illuminate\View\ViewServiceProvider;
-use Monolog\Formatter\LineFormatter;
-use Monolog\Handler\RotatingFileHandler;
-use Monolog\Level;
-use Monolog\Logger;
-use Psr\Log\LoggerInterface;
class InstalledSite implements SiteInterface
{
@@ -69,11 +31,10 @@ class InstalledSite implements SiteInterface
*
* @return InstalledApp
*/
- public function bootApp(): AppInterface
+ public function init(): AppInterface
{
return new InstalledApp(
- $this->bootLaravel(),
- $this->config
+ $this->createApp()
);
}
@@ -88,48 +49,14 @@ class InstalledSite implements SiteInterface
return $this;
}
- protected function bootLaravel(): ApplicationContract
+ protected function createApp(): ApplicationContract
{
$app = new Application($this->paths);
$app->instance('env', $this->config->environment());
$app->instance('flarum.config', $this->config);
- $app->alias('flarum.config', Config::class);
$app->instance('flarum.debug', $this->config->inDebugMode());
$app->instance('config', $this->getIlluminateConfig());
- $app->instance('flarum.maintenance.handler', new MaintenanceModeHandler);
-
- $this->registerLogger($app);
- $this->registerCache($app);
-
- $app->register(AdminServiceProvider::class);
- $app->register(ApiServiceProvider::class);
- $app->register(BusServiceProvider::class);
- $app->register(ConsoleServiceProvider::class);
- $app->register(DatabaseServiceProvider::class);
- $app->register(DiscussionServiceProvider::class);
- $app->register(ExtensionServiceProvider::class);
- $app->register(ErrorServiceProvider::class);
- $app->register(FilesystemServiceProvider::class);
- $app->register(FilterServiceProvider::class);
- $app->register(FormatterServiceProvider::class);
- $app->register(ForumServiceProvider::class);
- $app->register(FrontendServiceProvider::class);
- $app->register(GroupServiceProvider::class);
- $app->register(HashServiceProvider::class);
- $app->register(HttpServiceProvider::class);
- $app->register(LocaleServiceProvider::class);
- $app->register(MailServiceProvider::class);
- $app->register(NotificationServiceProvider::class);
- $app->register(PostServiceProvider::class);
- $app->register(QueueServiceProvider::class);
- $app->register(SearchServiceProvider::class);
- $app->register(SessionServiceProvider::class);
- $app->register(SettingsServiceProvider::class);
- $app->register(UpdateServiceProvider::class);
- $app->register(UserServiceProvider::class);
- $app->register(ValidationServiceProvider::class);
- $app->register(ViewServiceProvider::class);
$app->booting(function () use ($app) {
// Run all local-site extenders before booting service providers
@@ -140,11 +67,20 @@ class InstalledSite implements SiteInterface
}
});
- $app->boot();
-
return $app;
}
+ public function bootstrappers(): array
+ {
+ return [
+ \Flarum\Foundation\Bootstrap\RegisterMaintenanceHandler::class,
+ \Flarum\Foundation\Bootstrap\RegisterLogger::class,
+ \Flarum\Foundation\Bootstrap\RegisterCache::class,
+ \Flarum\Foundation\Bootstrap\RegisterCoreProviders::class,
+ \Flarum\Foundation\Bootstrap\BootProviders::class,
+ ];
+ }
+
protected function getIlluminateConfig(): ConfigRepository
{
return new ConfigRepository([
@@ -162,28 +98,4 @@ class InstalledSite implements SiteInterface
]
]);
}
-
- protected function registerLogger(Container $container): void
- {
- $logPath = $this->paths->storage.'/logs/flarum.log';
- $logLevel = $this->config->inDebugMode() ? Level::Debug : Level::Info;
- $handler = new RotatingFileHandler($logPath, 0, $logLevel);
- $handler->setFormatter(new LineFormatter(null, null, true, true));
-
- $container->instance('log', new Logger('flarum', [$handler]));
- $container->alias('log', LoggerInterface::class);
- }
-
- protected function registerCache(Container $container): void
- {
- $container->singleton('cache.store', function ($container) {
- return new CacheRepository($container->make('cache.filestore'));
- });
- $container->alias('cache.store', Repository::class);
-
- $container->singleton('cache.filestore', function () {
- return new FileStore(new Filesystem, $this->paths->storage.'/cache');
- });
- $container->alias('cache.filestore', Store::class);
- }
}
diff --git a/framework/core/src/Foundation/SafeBooter.php b/framework/core/src/Foundation/SafeBooter.php
new file mode 100644
index 000000000..15ac625a7
--- /dev/null
+++ b/framework/core/src/Foundation/SafeBooter.php
@@ -0,0 +1,97 @@
+app->boot();
+ } catch (Throwable $e) {
+ // Apply response code first so whatever happens, it's set before anything is printed
+ http_response_code(500);
+
+ try {
+ $this->cleanBootExceptionLog($e);
+ } catch (Throwable $e) {
+ // Ignore errors in logger. The important goal is to log the original error
+ }
+
+ $this->fallbackBootExceptionLog($e);
+ }
+ }
+
+ /**
+ * Attempt to log the boot exception in a clean way and stop the script execution.
+ * This means looking for debug mode and/or our normal error logger.
+ * There is always a risk for this to fail,
+ * for example if the container bindings aren't present
+ * or if there is a filesystem error.
+ * @param Throwable $error
+ * @throws Throwable
+ */
+ private function cleanBootExceptionLog(Throwable $error): void
+ {
+ if ($this->app->has('flarum.config') && resolve('flarum.config')->inDebugMode()) {
+ // If the application booted far enough for the config to be available, we will check for debug mode
+ // Since the config is loaded very early, it is very likely to be available from the container
+ $message = $error->getMessage();
+ $file = $error->getFile();
+ $line = $error->getLine();
+ $type = get_class($error);
+
+ echo <<
+ thrown in $file on line $line
+
+
$error+ERROR; + exit(1); + } elseif ($this->app->has(LoggerInterface::class)) { + // If the application booted far enough for the logger to be available, we will log the error there + // Considering most boot errors are related to database or extensions, the logger should already be loaded + // We check for LoggerInterface binding because it's a constructor dependency of LogReporter, + // then instantiate LogReporter through the container for automatic dependency injection + resolve(LogReporter::class)->report($error); + + echo 'Flarum encountered a boot error. Details have been logged to the Flarum log file.'; + exit(1); + } + } + + /** + * If the clean logging doesn't work, then we have a last opportunity. + * Here we need to be extra careful not to include anything that might be sensitive on the page. + * + * @throws Throwable + */ + private function fallbackBootExceptionLog(Throwable $error): void + { + echo 'Flarum encountered a boot error. Details have been logged to the system PHP log file.
$error-ERROR; - exit(1); - } elseif ($container->has(LoggerInterface::class)) { - // If the application booted far enough for the logger to be available, we will log the error there - // Considering most boot errors are related to database or extensions, the logger should already be loaded - // We check for LoggerInterface binding because it's a constructor dependency of LogReporter, - // then instantiate LogReporter through the container for automatic dependency injection - resolve(LogReporter::class)->report($error); - - echo 'Flarum encountered a boot error. Details have been logged to the Flarum log file.'; - exit(1); - } - } - - /** - * If the clean logging doesn't work, then we have a last opportunity. - * Here we need to be extra careful not to include anything that might be sensitive on the page. - * - * @throws Throwable - */ - private function fallbackBootExceptionLog(Throwable $error): void - { - echo 'Flarum encountered a boot error. Details have been logged to the system PHP log file.