diff --git a/src/Console/Server.php b/src/Console/Server.php index c5a8d6b4d..a65ef9b28 100644 --- a/src/Console/Server.php +++ b/src/Console/Server.php @@ -12,74 +12,37 @@ namespace Flarum\Console; use Flarum\Console\Event\Configuring; -use Flarum\Database\Console\GenerateMigrationCommand; -use Flarum\Database\Console\MigrateCommand; -use Flarum\Database\Console\ResetCommand; use Flarum\Foundation\Application; -use Flarum\Foundation\Console\CacheClearCommand; -use Flarum\Foundation\Console\InfoCommand; -use Flarum\Foundation\Site; -use Flarum\Install\Console\InstallCommand; -use Flarum\Install\InstallServiceProvider; use Illuminate\Contracts\Events\Dispatcher; use Symfony\Component\Console\Application as ConsoleApplication; class Server { - /** - * @param Site $site - * @return Server - */ - public static function fromSite(Site $site) - { - return new static($site->boot()); - } + protected $commands; - public function __construct(Application $app) + public function __construct(array $commands) { - $this->app = $app; + $this->commands = $commands; } public function listen() { - $console = $this->getConsoleApplication(); + $console = new ConsoleApplication('Flarum', Application::VERSION); + + foreach ($this->commands as $command) { + $console->add($command); + } + + $this->extend($console); exit($console->run()); } - /** - * @return ConsoleApplication - */ - protected function getConsoleApplication() + private function extend(ConsoleApplication $console) { - $console = new ConsoleApplication('Flarum', $this->app->version()); + $app = Application::getInstance(); - $this->app->register(InstallServiceProvider::class); - - $commands = [ - InstallCommand::class, - MigrateCommand::class, - ResetCommand::class, - GenerateMigrationCommand::class, - ]; - - if ($this->app->isInstalled()) { - $commands = array_merge($commands, [ - InfoCommand::class, - CacheClearCommand::class - ]); - } - - foreach ($commands as $command) { - $console->add($this->app->make( - $command, - ['config' => $this->app->isInstalled() ? $this->app->make('flarum.config') : []] - )); - } - - $events = $this->app->make(Dispatcher::class); - $events->fire(new Configuring($this->app, $console)); - - return $console; + $events = $app->make(Dispatcher::class); + $events->fire(new Configuring($app, $console)); } } diff --git a/src/Foundation/AppInterface.php b/src/Foundation/AppInterface.php new file mode 100644 index 000000000..927c7b42e --- /dev/null +++ b/src/Foundation/AppInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Foundation; + +interface AppInterface +{ + /** + * @return \Psr\Http\Server\RequestHandlerInterface + */ + public function getRequestHandler(); + + /** + * @return \Symfony\Component\Console\Command\Command[] + */ + public function getConsoleCommands(); +} diff --git a/src/Foundation/InstalledApp.php b/src/Foundation/InstalledApp.php new file mode 100644 index 000000000..1b0c574bb --- /dev/null +++ b/src/Foundation/InstalledApp.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Foundation; + +use Flarum\Database\Console\GenerateMigrationCommand; +use Flarum\Database\Console\MigrateCommand; +use Flarum\Database\Console\ResetCommand; +use Flarum\Foundation\Console\CacheClearCommand; +use Flarum\Foundation\Console\InfoCommand; +use Flarum\Http\Middleware\DispatchRoute; +use Flarum\Settings\SettingsRepositoryInterface; +use Zend\Diactoros\Response\HtmlResponse; +use Zend\Stratigility\MiddlewarePipe; +use function Zend\Stratigility\middleware; +use function Zend\Stratigility\path; + +class InstalledApp implements AppInterface +{ + /** + * @var Application + */ + protected $laravel; + + /** + * @var array + */ + protected $config; + + public function __construct(Application $laravel, array $config) + { + $this->laravel = $laravel; + $this->config = $config; + } + + /** + * @return \Psr\Http\Server\RequestHandlerInterface + */ + public function getRequestHandler() + { + if ($this->inMaintenanceMode()) { + return $this->getMaintenanceMiddleware(); + } elseif ($this->needsUpdate()) { + return $this->getUpdaterMiddleware(); + } + + $pipe = new MiddlewarePipe; + + $pipe->pipe($this->subPath('api', 'flarum.api.middleware')); + $pipe->pipe($this->subPath('admin', 'flarum.admin.middleware')); + $pipe->pipe($this->subPath('', 'flarum.forum.middleware')); + + return $pipe; + } + + private function inMaintenanceMode(): bool + { + return $this->config['offline'] ?? false; + } + + /** + * @return \Psr\Http\Server\RequestHandlerInterface + */ + private function getMaintenanceMiddleware() + { + $pipe = new MiddlewarePipe; + + $pipe->pipe(middleware(function () { + // FIXME: Fix path to 503.html + // TODO: FOR API render JSON-API error document for HTTP 503 + return new HtmlResponse( + file_get_contents(__DIR__.'/../../503.html'), 503 + ); + })); + + return $pipe; + } + + private function needsUpdate(): bool + { + $settings = $this->laravel->make(SettingsRepositoryInterface::class); + $version = $settings->get('version'); + + return $version !== Application::VERSION; + } + + /** + * @return \Psr\Http\Server\RequestHandlerInterface + */ + public function getUpdaterMiddleware() + { + $pipe = new MiddlewarePipe; + $pipe->pipe( + $this->laravel->make( + DispatchRoute::class, + ['routes' => $this->laravel->make('flarum.update.routes')] + ) + ); + + return $pipe; + } + + private function subPath($pathName, $middlewareStack) + { + return path( + parse_url($this->laravel->url($pathName), PHP_URL_PATH) ?: '/', + $this->laravel->make($middlewareStack) + ); + } + + /** + * @return \Symfony\Component\Console\Command\Command[] + */ + public function getConsoleCommands() + { + return [ + $this->laravel->make(GenerateMigrationCommand::class), + $this->laravel->make(InfoCommand::class, ['config' => $this->config]), + $this->laravel->make(MigrateCommand::class), + $this->laravel->make(ResetCommand::class), + $this->laravel->make(CacheClearCommand::class), + ]; + } +} diff --git a/src/Foundation/InstalledSite.php b/src/Foundation/InstalledSite.php new file mode 100644 index 000000000..dd6740a30 --- /dev/null +++ b/src/Foundation/InstalledSite.php @@ -0,0 +1,221 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Foundation; + +use Flarum\Admin\AdminServiceProvider; +use Flarum\Api\ApiServiceProvider; +use Flarum\Bus\BusServiceProvider as BusProvider; +use Flarum\Database\DatabaseServiceProvider; +use Flarum\Database\MigrationServiceProvider; +use Flarum\Discussion\DiscussionServiceProvider; +use Flarum\Extension\ExtensionServiceProvider; +use Flarum\Formatter\FormatterServiceProvider; +use Flarum\Forum\ForumServiceProvider; +use Flarum\Frontend\FrontendServiceProvider; +use Flarum\Group\GroupServiceProvider; +use Flarum\Locale\LocaleServiceProvider; +use Flarum\Notification\NotificationServiceProvider; +use Flarum\Post\PostServiceProvider; +use Flarum\Search\SearchServiceProvider; +use Flarum\Settings\SettingsRepositoryInterface; +use Flarum\Settings\SettingsServiceProvider; +use Flarum\Update\UpdateServiceProvider; +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\Filesystem\Filesystem; +use Illuminate\Filesystem\FilesystemServiceProvider; +use Illuminate\Hashing\HashServiceProvider; +use Illuminate\Mail\MailServiceProvider; +use Illuminate\Validation\ValidationServiceProvider; +use Illuminate\View\ViewServiceProvider; +use Monolog\Formatter\LineFormatter; +use Monolog\Handler\StreamHandler; +use Monolog\Logger; +use Psr\Log\LoggerInterface; + +class InstalledSite implements SiteInterface +{ + /** + * @var string + */ + protected $basePath; + + /** + * @var string + */ + protected $publicPath; + + /** + * @var string + */ + protected $storagePath; + + /** + * @var array + */ + protected $config; + + public function __construct($basePath, $publicPath, array $config) + { + $this->basePath = $basePath; + $this->publicPath = $publicPath; + $this->config = $config; + } + + /** + * Create and boot a Flarum application instance. + * + * @return AppInterface + */ + public function bootApp(): AppInterface + { + return new InstalledApp( + $this->bootLaravel(), + $this->config + ); + } + + /** + * @param $storagePath + * @return static + */ + public function setStoragePath($storagePath) + { + $this->storagePath = $storagePath; + + return $this; + } + + protected function bootLaravel(): Application + { + $laravel = new Application($this->basePath, $this->publicPath); + + if ($this->storagePath) { + $laravel->useStoragePath($this->storagePath); + } + + $laravel->instance('env', 'production'); + $laravel->instance('flarum.config', $this->config); + $laravel->instance('config', $config = $this->getIlluminateConfig($laravel)); + + $this->registerLogger($laravel); + $this->registerCache($laravel); + + $laravel->register(DatabaseServiceProvider::class); + $laravel->register(MigrationServiceProvider::class); + $laravel->register(SettingsServiceProvider::class); + $laravel->register(LocaleServiceProvider::class); + $laravel->register(BusServiceProvider::class); + $laravel->register(FilesystemServiceProvider::class); + $laravel->register(HashServiceProvider::class); + $laravel->register(MailServiceProvider::class); + $laravel->register(ViewServiceProvider::class); + $laravel->register(ValidationServiceProvider::class); + + $laravel->register(BusProvider::class); + + $settings = $laravel->make(SettingsRepositoryInterface::class); + + $config->set('mail.driver', $settings->get('mail_driver')); + $config->set('mail.host', $settings->get('mail_host')); + $config->set('mail.port', $settings->get('mail_port')); + $config->set('mail.from.address', $settings->get('mail_from')); + $config->set('mail.from.name', $settings->get('forum_title')); + $config->set('mail.encryption', $settings->get('mail_encryption')); + $config->set('mail.username', $settings->get('mail_username')); + $config->set('mail.password', $settings->get('mail_password')); + + $laravel->register(DiscussionServiceProvider::class); + $laravel->register(FormatterServiceProvider::class); + $laravel->register(FrontendServiceProvider::class); + $laravel->register(GroupServiceProvider::class); + $laravel->register(NotificationServiceProvider::class); + $laravel->register(PostServiceProvider::class); + $laravel->register(SearchServiceProvider::class); + $laravel->register(UserServiceProvider::class); + $laravel->register(UpdateServiceProvider::class); + + $laravel->register(ApiServiceProvider::class); + $laravel->register(ForumServiceProvider::class); + $laravel->register(AdminServiceProvider::class); + + $laravel->register(ExtensionServiceProvider::class); + + $laravel->boot(); + + return $laravel; + } + + /** + * @param Application $app + * @return ConfigRepository + */ + protected function getIlluminateConfig(Application $app) + { + return new ConfigRepository([ + 'view' => [ + 'paths' => [], + 'compiled' => $app->storagePath().'/views', + ], + 'mail' => [ + 'driver' => 'mail', + ], + 'filesystems' => [ + 'default' => 'local', + 'cloud' => 's3', + 'disks' => [ + 'flarum-assets' => [ + 'driver' => 'local', + 'root' => $app->publicPath().'/assets', + 'url' => $app->url('assets') + ], + 'flarum-avatars' => [ + 'driver' => 'local', + 'root' => $app->publicPath().'/assets/avatars' + ] + ] + ], + 'session' => [ + 'lifetime' => 120, + 'files' => $app->storagePath().'/sessions', + 'cookie' => 'session' + ] + ]); + } + + protected function registerLogger(Application $app) + { + $logPath = $app->storagePath().'/logs/flarum.log'; + $handler = new StreamHandler($logPath, Logger::INFO); + $handler->setFormatter(new LineFormatter(null, null, true, true)); + + $app->instance('log', new Logger($app->environment(), [$handler])); + $app->alias('log', LoggerInterface::class); + } + + protected function registerCache(Application $app) + { + $app->singleton('cache.store', function ($app) { + return new CacheRepository($app->make('cache.filestore')); + }); + $app->alias('cache.store', Repository::class); + + $app->singleton('cache.filestore', function ($app) { + return new FileStore(new Filesystem, $app->storagePath().'/cache'); + }); + $app->alias('cache.filestore', Store::class); + } +} diff --git a/src/Foundation/Site.php b/src/Foundation/Site.php index 14a4f90da..dc58cb593 100644 --- a/src/Foundation/Site.php +++ b/src/Foundation/Site.php @@ -11,281 +11,53 @@ namespace Flarum\Foundation; -use Flarum\Admin\AdminServiceProvider; -use Flarum\Api\ApiServiceProvider; -use Flarum\Bus\BusServiceProvider as BusProvider; -use Flarum\Database\DatabaseServiceProvider; -use Flarum\Database\MigrationServiceProvider; -use Flarum\Discussion\DiscussionServiceProvider; -use Flarum\Extension\ExtensionServiceProvider; -use Flarum\Formatter\FormatterServiceProvider; -use Flarum\Forum\ForumServiceProvider; -use Flarum\Frontend\FrontendServiceProvider; -use Flarum\Group\GroupServiceProvider; -use Flarum\Locale\LocaleServiceProvider; -use Flarum\Notification\NotificationServiceProvider; -use Flarum\Post\PostServiceProvider; -use Flarum\Search\SearchServiceProvider; -use Flarum\Settings\SettingsRepositoryInterface; -use Flarum\Settings\SettingsServiceProvider; -use Flarum\User\UserServiceProvider; -use Illuminate\Bus\BusServiceProvider; -use Illuminate\Config\Repository as ConfigRepository; -use Illuminate\Filesystem\FilesystemServiceProvider; -use Illuminate\Hashing\HashServiceProvider; -use Illuminate\Mail\MailServiceProvider; -use Illuminate\Validation\ValidationServiceProvider; -use Illuminate\View\ViewServiceProvider; -use Monolog\Formatter\LineFormatter; -use Monolog\Handler\StreamHandler; -use Monolog\Logger; +use InvalidArgumentException; +use RuntimeException; -// TODO: This should be an interface maybe? class Site { /** - * @var Application + * @param array $paths + * @return SiteInterface */ - protected $app; - - /** - * @var string - */ - protected $basePath; - - /** - * @var string - */ - protected $publicPath; - - /** - * @var string - */ - protected $storagePath; - - /** - * @var array - */ - protected $config; - - protected $extenders = []; - - public function __construct() + public static function fromPaths(array $paths) { - $this->basePath = getcwd(); - $this->publicPath = $this->basePath; - } - - /** - * @return Application - */ - public function boot() - { - return $this->getApp(); - } - - /** - * @param $basePath - * @return static - */ - public function setBasePath($basePath) - { - $this->basePath = $basePath; - - return $this; - } - - /** - * @param $publicPath - * @return static - */ - public function setPublicPath($publicPath) - { - $this->publicPath = $publicPath; - - return $this; - } - - /** - * @param $storagePath - * @return static - */ - public function setStoragePath($storagePath) - { - $this->storagePath = $storagePath; - - return $this; - } - - /** - * @param array $config - * @return static - */ - public function setConfig(array $config) - { - $this->config = $config; - - return $this; - } - - protected function getConfig() - { - if (empty($this->config) && file_exists($file = $this->basePath.'/config.php')) { - $this->config = include $file; + if (! isset($paths['base'])) { + throw new InvalidArgumentException( + 'No base path given' + ); } - return $this->config; - } - - /** - * @return Application - */ - protected function getApp() - { - if ($this->app !== null) { - return $this->app; + if (! isset($paths['public'])) { + $paths['public'] = $paths['base']; } date_default_timezone_set('UTC'); - $app = new Application($this->basePath, $this->publicPath); - - if ($this->storagePath) { - $app->useStoragePath($this->storagePath); - } - - $app->instance('env', 'production'); - $app->instance('flarum.config', $this->getConfig()); - $app->instance('config', $config = $this->getIlluminateConfig($app)); - - $this->registerLogger($app); - - $this->registerCache($app); - - $app->register(DatabaseServiceProvider::class); - $app->register(MigrationServiceProvider::class); - $app->register(SettingsServiceProvider::class); - $app->register(LocaleServiceProvider::class); - $app->register(BusServiceProvider::class); - $app->register(FilesystemServiceProvider::class); - $app->register(HashServiceProvider::class); - $app->register(MailServiceProvider::class); - $app->register(ViewServiceProvider::class); - $app->register(ValidationServiceProvider::class); - - $app->register(BusProvider::class); - - if ($app->isInstalled() && $app->isUpToDate()) { - $settings = $app->make(SettingsRepositoryInterface::class); - - $config->set('mail.driver', $settings->get('mail_driver')); - $config->set('mail.host', $settings->get('mail_host')); - $config->set('mail.port', $settings->get('mail_port')); - $config->set('mail.from.address', $settings->get('mail_from')); - $config->set('mail.from.name', $settings->get('forum_title')); - $config->set('mail.encryption', $settings->get('mail_encryption')); - $config->set('mail.username', $settings->get('mail_username')); - $config->set('mail.password', $settings->get('mail_password')); - - $app->register(DiscussionServiceProvider::class); - $app->register(FormatterServiceProvider::class); - $app->register(FrontendServiceProvider::class); - $app->register(GroupServiceProvider::class); - $app->register(NotificationServiceProvider::class); - $app->register(PostServiceProvider::class); - $app->register(SearchServiceProvider::class); - $app->register(UserServiceProvider::class); - - $app->register(ApiServiceProvider::class); - $app->register(ForumServiceProvider::class); - $app->register(AdminServiceProvider::class); - - foreach ($this->extenders as $extender) { - // TODO: Create extenders architecture - // $extender->apply($app); - } - - $app->register(ExtensionServiceProvider::class); - } - - $app->boot(); - - $this->app = $app; - - return $app; - } - - /** - * @param Application $app - * @return ConfigRepository - */ - protected function getIlluminateConfig(Application $app) - { - return new ConfigRepository([ - 'view' => [ - 'paths' => [], - 'compiled' => $app->storagePath().'/views', - ], - 'mail' => [ - 'driver' => 'mail', - ], - 'filesystems' => [ - 'default' => 'local', - 'cloud' => 's3', - 'disks' => [ - 'flarum-assets' => [ - 'driver' => 'local', - 'root' => $app->publicPath().'/assets', - 'url' => $app->url('assets') - ], - 'flarum-avatars' => [ - 'driver' => 'local', - 'root' => $app->publicPath().'/assets/avatars' - ] - ] - ], - 'session' => [ - 'lifetime' => 120, - 'files' => $app->storagePath().'/sessions', - 'cookie' => 'session' - ] - ]); - } - - /** - * @param Application $app - */ - protected function registerLogger(Application $app) - { - $logger = new Logger($app->environment()); - $logPath = $app->storagePath().'/logs/flarum.log'; - - $handler = new StreamHandler($logPath, Logger::DEBUG); - $handler->setFormatter(new LineFormatter(null, null, true, true)); - - $logger->pushHandler($handler); - - $app->instance('log', $logger); - $app->alias('log', 'Psr\Log\LoggerInterface'); - } - - /** - * @param Application $app - */ - protected function registerCache(Application $app) - { - $app->singleton('cache.store', function ($app) { - return new \Illuminate\Cache\Repository($app->make('cache.filestore')); - }); - - $app->singleton('cache.filestore', function ($app) { - return new \Illuminate\Cache\FileStore( - new \Illuminate\Filesystem\Filesystem(), - $app->storagePath().'/cache' + if (static::hasConfigFile($paths['base'])) { + return new InstalledSite( + $paths['base'], + $paths['public'], + static::loadConfig($paths['base']) ); - }); + } else { + return new UninstalledSite($paths['base'], $paths['public']); + } + } - $app->alias('cache.filestore', 'Illuminate\Contracts\Cache\Store'); - $app->alias('cache.store', 'Illuminate\Contracts\Cache\Repository'); + private static function hasConfigFile($basePath) + { + return file_exists("$basePath/config.php"); + } + + private static function loadConfig($basePath): array + { + $config = include "$basePath/config.php"; + + if (! is_array($config)) { + throw new RuntimeException('config.php should return an array'); + } + + return $config; } } diff --git a/src/Foundation/SiteInterface.php b/src/Foundation/SiteInterface.php new file mode 100644 index 000000000..9f5b1b97f --- /dev/null +++ b/src/Foundation/SiteInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Foundation; + +interface SiteInterface +{ + /** + * Create and boot a Flarum application instance. + * + * @return AppInterface + */ + public function bootApp(): AppInterface; +} diff --git a/src/Foundation/UninstalledSite.php b/src/Foundation/UninstalledSite.php new file mode 100644 index 000000000..b655e150d --- /dev/null +++ b/src/Foundation/UninstalledSite.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Foundation; + +use Flarum\Install\Installer; +use Flarum\Install\InstallServiceProvider; +use Flarum\Locale\LocaleServiceProvider; +use Flarum\Settings\SettingsRepositoryInterface; +use Flarum\Settings\UninstalledSettingsRepository; +use Illuminate\Config\Repository as ConfigRepository; +use Illuminate\Contracts\Events\Dispatcher; +use Illuminate\Filesystem\FilesystemServiceProvider; +use Illuminate\Validation\ValidationServiceProvider; +use Illuminate\View\Engines\EngineResolver; +use Illuminate\View\Engines\PhpEngine; +use Illuminate\View\FileViewFinder; +use Monolog\Formatter\LineFormatter; +use Monolog\Handler\StreamHandler; +use Monolog\Logger; +use Psr\Log\LoggerInterface; + +class UninstalledSite implements SiteInterface +{ + /** + * @var string + */ + protected $basePath; + + /** + * @var string + */ + protected $publicPath; + + /** + * @var string + */ + protected $storagePath; + + public function __construct($basePath, $publicPath) + { + $this->basePath = $basePath; + $this->publicPath = $publicPath; + } + + /** + * Create and boot a Flarum application instance. + * + * @return AppInterface + */ + public function bootApp(): AppInterface + { + return new Installer( + $this->bootLaravel() + ); + } + + private function bootLaravel(): Application + { + $laravel = new Application($this->basePath, $this->publicPath); + + if ($this->storagePath) { + $laravel->useStoragePath($this->storagePath); + } + + $laravel->instance('env', 'production'); + $laravel->instance('flarum.config', []); + $laravel->instance('config', $config = $this->getIlluminateConfig($laravel)); + + $this->registerLogger($laravel); + + $laravel->register(LocaleServiceProvider::class); + $laravel->register(FilesystemServiceProvider::class); + $laravel->register(ValidationServiceProvider::class); + + $laravel->register(InstallServiceProvider::class); + + $laravel->singleton( + SettingsRepositoryInterface::class, + UninstalledSettingsRepository::class + ); + + $laravel->singleton('view', function ($app) { + $engines = new EngineResolver(); + $engines->register('php', function () { + return new PhpEngine(); + }); + $finder = new FileViewFinder($app->make('files'), []); + $dispatcher = $app->make(Dispatcher::class); + + return new \Illuminate\View\Factory( + $engines, $finder, $dispatcher + ); + }); + + $laravel->boot(); + + return $laravel; + } + + /** + * @param Application $app + * @return ConfigRepository + */ + protected function getIlluminateConfig(Application $app) + { + return new ConfigRepository([ + 'session' => [ + 'lifetime' => 120, + 'files' => $app->storagePath().'/sessions', + 'cookie' => 'session' + ] + ]); + } + + protected function registerLogger(Application $app) + { + $logPath = $app->storagePath().'/logs/flarum-installer.log'; + $handler = new StreamHandler($logPath, Logger::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/src/Http/Server.php b/src/Http/Server.php index 9583d9180..825dc4bce 100644 --- a/src/Http/Server.php +++ b/src/Http/Server.php @@ -11,43 +11,22 @@ namespace Flarum\Http; -use Flarum\Foundation\Application; -use Flarum\Foundation\Site; -use Flarum\Http\Middleware\DispatchRoute; -use Flarum\Http\Middleware\HandleErrors; -use Flarum\Http\Middleware\StartSession; -use Flarum\Install\InstallServiceProvider; -use Flarum\Update\UpdateServiceProvider; -use Psr\Http\Message\ResponseInterface as Response; -use Psr\Http\Message\ServerRequestInterface as Request; -use Psr\Http\Server\MiddlewareInterface as Middleware; -use Psr\Http\Server\RequestHandlerInterface as Handler; -use Zend\Diactoros\Response\HtmlResponse; +use Psr\Http\Server\RequestHandlerInterface; use Zend\Diactoros\Server as DiactorosServer; -use Zend\Stratigility\MiddlewarePipe; -use function Zend\Stratigility\middleware; -use function Zend\Stratigility\path; -class Server implements Middleware, Handler +class Server { - /** - * @param Site $site - * @return Server - */ - public static function fromSite(Site $site) - { - return new static($site->boot()); - } + protected $requestHandler; - public function __construct(Application $app) + public function __construct(RequestHandlerInterface $requestHandler) { - $this->app = $app; + $this->requestHandler = $requestHandler; } public function listen() { DiactorosServer::createServer( - [$this, 'handle'], + [$this->requestHandler, 'handle'], $_SERVER, $_GET, $_POST, @@ -55,105 +34,4 @@ class Server implements Middleware, Handler $_FILES )->listen(); } - - /** - * Use as PSR-15 middleware. - */ - public function process(Request $request, Handler $handler): Response - { - $middleware = $this->getMiddleware($request->getUri()->getPath()); - - return $middleware->process($request, $handler); - } - - /** - * Use as PSR-15 request handler. - */ - public function handle(Request $request): Response - { - $middleware = $this->getMiddleware($request->getUri()->getPath()); - - return $middleware->handle($request); - } - - /** - * @param string $requestPath - * @return MiddlewarePipe - */ - protected function getMiddleware($requestPath) - { - $pipe = new MiddlewarePipe; - - if (! $this->app->isInstalled()) { - return $this->getInstallerMiddleware($pipe); - } - - if ($this->app->isDownForMaintenance()) { - return $this->getMaintenanceMiddleware($pipe); - } - - if (! $this->app->isUpToDate()) { - return $this->getUpdaterMiddleware($pipe); - } - - $api = parse_url($this->app->url('api'), PHP_URL_PATH); - $admin = parse_url($this->app->url('admin'), PHP_URL_PATH); - $forum = parse_url($this->app->url(''), PHP_URL_PATH) ?: '/'; - - if ($this->pathStartsWith($requestPath, $api)) { - $pipe->pipe(path($api, $this->app->make('flarum.api.middleware'))); - } elseif ($this->pathStartsWith($requestPath, $admin)) { - $pipe->pipe(path($admin, $this->app->make('flarum.admin.middleware'))); - } else { - $pipe->pipe(path($forum, $this->app->make('flarum.forum.middleware'))); - } - - return $pipe; - } - - private function pathStartsWith($path, $prefix) - { - return $path === $prefix || starts_with($path, "$prefix/"); - } - - protected function getInstallerMiddleware(MiddlewarePipe $pipe) - { - $this->app->register(InstallServiceProvider::class); - - // FIXME: Re-enable HandleErrors middleware, if possible - // (Right now it tries to resolve a database connection because of the injected settings repo instance) - // We could register a different settings repo when Flarum is not installed - //$pipe->pipe($this->app->make(HandleErrors::class, ['debug' => true])); - //$pipe->pipe($this->app->make(StartSession::class)); - $pipe->pipe($this->app->make(DispatchRoute::class, ['routes' => $this->app->make('flarum.install.routes')])); - - return $pipe; - } - - protected function getMaintenanceMiddleware(MiddlewarePipe $pipe) - { - $pipe->pipe(middleware(function () { - return new HtmlResponse(file_get_contents($this->getErrorDir().'/503.html', 503)); - })); - - // TODO: FOR API render JSON-API error document for HTTP 503 - - return $pipe; - } - - protected function getUpdaterMiddleware(MiddlewarePipe $pipe) - { - $this->app->register(UpdateServiceProvider::class); - - $pipe->pipe($this->app->make(DispatchRoute::class, ['routes' => $this->app->make('flarum.update.routes')])); - - // TODO: FOR API render JSON-API error document for HTTP 503 - - return $pipe; - } - - private function getErrorDir() - { - return __DIR__.'/../../error'; - } } diff --git a/src/Install/Installer.php b/src/Install/Installer.php new file mode 100644 index 000000000..0ca0253e7 --- /dev/null +++ b/src/Install/Installer.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Install; + +use Flarum\Foundation\AppInterface; +use Flarum\Foundation\Application; +use Flarum\Http\Middleware\DispatchRoute; +use Flarum\Http\Middleware\HandleErrorsWithWhoops; +use Flarum\Http\Middleware\StartSession; +use Flarum\Install\Console\InstallCommand; +use Zend\Stratigility\MiddlewarePipe; + +class Installer implements AppInterface +{ + /** + * @var Application + */ + protected $laravel; + + public function __construct(Application $laravel) + { + $this->laravel = $laravel; + } + + /** + * @return \Psr\Http\Server\RequestHandlerInterface + */ + public function getRequestHandler() + { + $pipe = new MiddlewarePipe; + $pipe->pipe($this->laravel->make(HandleErrorsWithWhoops::class)); + #$pipe->pipe($this->laravel->make(StartSession::class)); + $pipe->pipe( + $this->laravel->make( + DispatchRoute::class, + ['routes' => $this->laravel->make('flarum.install.routes')] + ) + ); + + return $pipe; + } + + /** + * @return \Symfony\Component\Console\Command\Command[] + */ + public function getConsoleCommands() + { + return [ + $this->laravel->make(InstallCommand::class), + ]; + } +} diff --git a/src/Settings/UninstalledSettingsRepository.php b/src/Settings/UninstalledSettingsRepository.php new file mode 100644 index 000000000..fb8d1af34 --- /dev/null +++ b/src/Settings/UninstalledSettingsRepository.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Settings; + +class UninstalledSettingsRepository implements SettingsRepositoryInterface +{ + public function all() + { + return []; + } + + public function get($key, $default = null) + { + return $default; + } + + public function set($key, $value) + { + // Do nothing + } + + public function delete($keyLike) + { + // Do nothing + } +}