guard(); $checks = $this->installation->checks(); return $this->render('install/check.html.twig', [ 'step' => 1, 'checks' => $checks, 'ready' => $this->installation->ready($checks), ]); } #[Route('/install/datenbank', name: 'install_database', methods: ['GET', 'POST'], priority: 10)] public function database(Request $request): Response { $this->guard(); $error = null; $driver = $request->request->getString('driver', 'sqlite'); if ($request->isMethod('POST') && $this->signed($request, 'datenbank')) { $input = [ 'host' => $request->request->getString('host', '127.0.0.1'), 'port' => $request->request->getString('port', '3306'), 'name' => $request->request->getString('name', 'cms'), 'user' => $request->request->getString('user'), 'password' => $request->request->getString('password'), ]; $result = $this->installation->testDatabase('mysql' === $driver ? 'mysql' : 'sqlite', $input); $error = $result['error']; if (null === $error) { try { $this->installation->writeEnvironment(['APP_ENV' => 'prod', 'APP_DEBUG' => '0', 'DATABASE_URL' => $result['url']]); // The new connection only exists in the next request, because the environment // file is read while booting. That is also why this is a redirect and not a // rendered page: the migration screen has to talk to the new database. return $this->redirectToRoute('install_migration'); } catch (\RuntimeException $e) { $error = $e->getMessage(); } } } return $this->render('install/database.html.twig', [ 'step' => 2, 'driver' => $driver, 'error' => $error, 'values' => $request->request->all(), 'mysql' => \extension_loaded('pdo_mysql'), // SQLite nur, wenn die Fassung die Tabellenfunktionen kennt, mit denen Doctrine das // Schema liest - sonst scheitert erst der naechste Schritt, und zwar unverstaendlich. 'sqlite' => \extension_loaded('pdo_sqlite') && null !== $this->installation->sqliteVersion() && version_compare((string) $this->installation->sqliteVersion(), Installation::MIN_SQLITE, '>='), 'sqliteVersion' => $this->installation->sqliteVersion(), 'minSqlite' => Installation::MIN_SQLITE, ...$this->token('datenbank'), ]); } #[Route('/install/migration', name: 'install_migration', methods: ['GET', 'POST'], priority: 10)] public function migration(Request $request): Response { $this->guard(); if (!$this->installation->environmentWritten()) { return $this->redirectToRoute('install_database'); } $error = null; $applied = null; if ($request->isMethod('POST') && $this->signed($request, 'migration')) { @set_time_limit(0); try { $applied = $this->installation->migrate(); return $this->redirectToRoute('install_website'); } catch (\Throwable $e) { $error = $e->getMessage(); } } return $this->render('install/migration.html.twig', [ 'step' => 3, 'pending' => $error ? [] : $this->pending(), 'applied' => $applied, 'error' => $error, ...$this->token('migration'), ]); } #[Route('/install/website', name: 'install_website', methods: ['GET', 'POST'], priority: 10)] public function website(Request $request): Response { $this->guard(); if (!$this->installation->schemaReady()) { return $this->redirectToRoute('install_migration'); } $error = null; if ($request->isMethod('POST') && $this->signed($request, 'website')) { try { $this->installation->createSite( $request->request->getString('name'), $request->request->getString('origin'), $request->request->getString('locale', 'de'), ); return $this->redirectToRoute('install_account'); } catch (InvalidPage|\RuntimeException $e) { $error = $e->getMessage(); } } return $this->render('install/website.html.twig', [ 'step' => 4, 'error' => $error, 'values' => $request->request->all(), // The address the browser is on is almost always the right one, so it is prefilled. 'origin' => $request->getSchemeAndHttpHost(), ...$this->token('website'), ]); } #[Route('/install/konto', name: 'install_account', methods: ['GET', 'POST'], priority: 10)] public function account(Request $request): Response { $this->guard(); if (!$this->installation->siteReady()) { return $this->redirectToRoute('install_website'); } $error = null; if ($request->isMethod('POST') && $this->signed($request, 'konto')) { try { $this->installation->createAdmin( $request->request->getString('username'), $request->request->getString('password'), $request->request->getString('repeat'), ); // The last screen is rendered here, not after a redirect: one request later this // route is gone, because the account it just created ends the installation. return $this->render('install/done.html.twig', [ 'step' => 6, 'username' => strtolower(trim($request->request->getString('username'))), ]); } catch (InvalidPage $e) { $error = $e->getMessage(); } } return $this->render('install/account.html.twig', [ 'step' => 5, 'error' => $error, 'username' => $request->request->getString('username'), ...$this->token('konto'), ]); } /** Reading the pending list must never be the reason the screen cannot be shown. */ private function pending(): array { try { return $this->installation->pendingMigrations(); } catch (\Throwable) { return []; } } private function guard(): void { if ($this->installation->isInstalled()) { throw new NotFoundHttpException('Diese Installation ist abgeschlossen.'); } } private function token(string $step): array { $issued = time(); return ['issued' => $issued, 'signature' => $this->installation->sign($step, $issued)]; } private function signed(Request $request, string $step): bool { return $this->installation->verify($step, $request->request->getInt('issued'), $request->request->getString('signature')); } }