Files
KantSites/src/Controller/SettingsController.php
T
kantarci 16da844934
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
feat: assign custom 404 pages with the website theme (1.8.0)
2026-09-14 12:18:33 +02:00

184 lines
8.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Controller;
use App\Content\Consent;
use App\Content\DemoContent;
use App\Content\MediaLibrary;
use App\Content\NotFoundPage;
use App\Content\PageRepository;
use App\Content\RedirectRepository;
use App\Content\SiteSettings;
use App\Content\Theme;
use App\Domain\InvalidPage;
use App\Domain\StaleWrite;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
final class SettingsController extends AbstractController
{
public function __construct(private SiteSettings $settings, private RedirectRepository $redirects, private PageRepository $pages, private MediaLibrary $media, private Theme $theme, private NotFoundPage $notFoundPage)
{
}
#[Route('/%kant.admin_path%/settings', name: 'admin_settings', methods: ['GET'])]
public function index(Request $request): Response
{
$choosable = [];
foreach ($this->pages->listForEditor() as $page) {
// Only a published page can serve as the root; a draft would answer every visit with 404.
if ('page' === $page['type'] && null !== $page['published_revision_id']) {
$document = json_decode($page['document'] ?? '{}', true, 512, JSON_THROW_ON_ERROR);
$choosable[] = ['path' => $page['path'], 'title' => $document['title'] ?? $page['path']];
}
}
return $this->render('admin/settings.html.twig', [
'settings' => $this->settings->load(),
'notFoundSelection' => $this->notFoundPage->selected(),
'redirects' => $this->redirects->all($request->query->getInt('seite', 1)),
'choosableHome' => $choosable,
'consentGroups' => Consent::GROUPS,
'missingLegal' => $this->settings->missingLegalPages(),
'consentGroupHelp' => Consent::GROUP_HELP,
// Für das Symbol der Website: die Mediathek zur Auswahl, die neuesten zuerst.
'images' => $this->media->page(1, false, 96)['items'],
// Fuer die Farbfelder: dieselbe Palette, die auch der Editor anbietet.
'palette' => $this->theme->load()['colors'],
]);
}
#[Route('/%kant.admin_path%/settings/company', name: 'admin_settings_save', methods: ['POST'])]
public function save(Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_EDITOR');
if (!$this->isCsrfTokenValid('settings', $request->request->getString('_csrf_token'))) {
return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
}
try {
$this->settings->save($request->request->all());
} catch (InvalidPage $e) {
return $this->back($e->getMessage());
}
return $this->back('Die Unternehmensdaten wurden gespeichert.', 'success');
}
#[Route('/%kant.admin_path%/settings/not-found', name: 'admin_not_found_save', methods: ['POST'])]
public function saveNotFound(Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_PUBLISHER');
if (!$this->isCsrfTokenValid('settings', $request->request->getString('_csrf_token'))) {
return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
}
try {
$expectedId = $request->request->getString('expectedId');
if ('create' === $request->request->getString('action')) {
$id = $this->notFoundPage->create($expectedId);
$this->addFlash('success', 'Die 404-Vorlage wurde als Entwurf angelegt und zugewiesen. Nach dem Veröffentlichen ersetzt sie die Standard-404.');
return $this->redirectToRoute('admin_editor', ['id' => $id]);
}
$id = $request->request->getString('notFoundPageId');
$this->settings->assignNotFoundPage($id, $expectedId);
$selection = $this->notFoundPage->selected();
$message = '' === $id ? 'Die Standard-404 im Website-Design ist wieder aktiv.'
: ($selection['published'] ? 'Die 404-Seite wurde zugewiesen.' : 'Die Seite wurde zugewiesen. Bis zu ihrer Veröffentlichung erscheint die Standard-404.');
$this->addFlash('success', $message);
} catch (InvalidPage|StaleWrite $error) {
$this->addFlash('error', $error->getMessage());
}
return $this->redirectToRoute('admin_settings', ['_fragment' => 'not-found']);
}
#[Route('/%kant.admin_path%/settings/redirects', name: 'admin_redirect_save', methods: ['POST'])]
public function saveRedirect(Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_EDITOR');
if (!$this->isCsrfTokenValid('settings', $request->request->getString('_csrf_token'))) {
return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
}
$remove = $request->request->getString('remove');
if ('' !== $remove) {
$this->redirects->delete($remove);
return $this->back('Die Weiterleitung wurde entfernt.', 'success');
}
try {
$this->redirects->save(
$request->request->getString('from'),
$request->request->getString('to'),
$request->request->getInt('status', 301),
);
} catch (InvalidPage $e) {
return $this->back($e->getMessage());
}
return $this->back('Die Weiterleitung wurde gespeichert.', 'success');
}
/**
* Creates the privacy statement and the imprint, with a skeleton whose gaps are marked.
*
* The pages are mandatory, the text is not something a CMS can write: what gets created is the
* structure with every required item named and marked as still to be filled in.
*/
#[Route('/%kant.admin_path%/settings/rechtliches', name: 'admin_legal_pages', methods: ['POST'])]
public function legalPages(Request $request): Response
{
$this->denyAccessUnlessGranted('ROLE_EDITOR');
if (!$this->isCsrfTokenValid('settings', $request->request->getString('_csrf_token'))) {
return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.');
}
$settings = $this->settings->load();
$created = [];
try {
foreach (DemoContent::LEGAL as $slug => $label) {
$key = 'datenschutz' === $slug ? 'privacyPath' : 'imprintPath';
// An existing page is never overwritten - it may already carry the real text.
$existing = null !== $this->pages->findPublished($slug) || $this->pageExists($slug);
if (!$existing) {
$id = $this->pages->createPage($slug, null, 'page', DemoContent::legalPage($slug));
$page = $this->pages->findForEditor($id);
$this->pages->publish($id, $page['draft_revision_id'], $page['version']);
$created[] = $label;
}
$settings[$key] = $slug;
}
$this->settings->save([...$settings, 'consentGroups' => $settings['consentGroups'], 'sameAs' => implode('
', $settings['sameAs'])]);
} catch (InvalidPage $e) {
return $this->back($e->getMessage());
}
return $this->back(
[] === $created
? 'Die Seiten waren schon vorhanden und sind jetzt verknüpft. Der Inhalt bleibt unverändert.'
: sprintf('%s angelegt und verknüpft. Beide Seiten sind veröffentlicht und müssen noch ausgefüllt werden – die Pflichtangaben sind darin markiert.', implode(' und ', $created)),
'success',
);
}
/** Also finds a page that exists but is not published yet. */
private function pageExists(string $path): bool
{
foreach ($this->pages->listForEditor() as $page) {
if ($path === $page['path']) {
return true;
}
}
return false;
}
private function back(string $message, string $type = 'error'): Response
{
$this->addFlash($type, $message);
return $this->redirectToRoute('admin_settings');
}
}