From 72354fa42436c3fb5c8a4708527446cdb939434e Mon Sep 17 00:00:00 2001
From: Kevin Ditscheid <kevin.ditscheid@sgalinski.de>
Date: Fri, 24 Nov 2023 19:37:19 +0100
Subject: [PATCH] [TASK] Remove deprecated plugin preview and
 allowTableOnStandardPages

---
 ...geContentPreviewRenderingEventListener.php |  61 +++++
 .../Hooks/PageLayoutView/PluginRenderer.php   | 122 ----------
 Classes/Preview/PreviewRenderer.php           | 110 ---------
 Classes/Preview/PreviewService.php            |  32 ++-
 Classes/Updates/DepartmentUpdateWizard.php    | 226 ------------------
 Configuration/Backend/Modules.php             |  19 ++
 Configuration/Services.php                    |   9 +-
 .../TCA/tx_sgjobs_domain_model_company.php    |   5 +-
 .../TCA/tx_sgjobs_domain_model_contact.php    |   5 +-
 .../TCA/tx_sgjobs_domain_model_department.php |   5 +-
 ...x_sgjobs_domain_model_experience_level.php |   5 +-
 .../TCA/tx_sgjobs_domain_model_job.php        |   5 +-
 ...tx_sgjobs_domain_model_job_application.php |   5 +-
 ext_localconf.php                             |   8 -
 ext_tables.php                                |  40 ----
 15 files changed, 134 insertions(+), 523 deletions(-)
 create mode 100644 Classes/EventListeners/PageContentPreviewRenderingEventListener.php
 delete mode 100644 Classes/Hooks/PageLayoutView/PluginRenderer.php
 delete mode 100644 Classes/Preview/PreviewRenderer.php
 delete mode 100644 Classes/Updates/DepartmentUpdateWizard.php
 create mode 100644 Configuration/Backend/Modules.php
 delete mode 100644 ext_tables.php

diff --git a/Classes/EventListeners/PageContentPreviewRenderingEventListener.php b/Classes/EventListeners/PageContentPreviewRenderingEventListener.php
new file mode 100644
index 00000000..879378e5
--- /dev/null
+++ b/Classes/EventListeners/PageContentPreviewRenderingEventListener.php
@@ -0,0 +1,61 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) sgalinski Internet Services (https://www.sgalinski.de)
+ *
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+namespace SGalinski\SgJobs\EventListeners;
+
+use SGalinski\SgJobs\Preview\PreviewService;
+use TYPO3\CMS\Backend\View\Event\PageContentPreviewRenderingEvent;
+
+class PageContentPreviewRenderingEventListener {
+
+	protected PreviewService $previewService;
+
+	public function __construct(PreviewService $previewService) {
+		$this->previewService = $previewService;
+	}
+
+	public function __invoke(PageContentPreviewRenderingEvent $event): void {
+		if ($event->getTable() === 'tt_content') {
+			$record = $event->getRecord();
+			switch ($record['list_type']) {
+				case 'sgjobs_jobapplication':
+					$event->setPreviewContent(
+						$this->previewService->getApplicationView($record)->render('JobApplication')
+					);
+					break;
+				case 'sgjobs_joblist':
+					$event->setPreviewContent(
+						$this->previewService->getJoblistView($record)->render('Joblist')
+					);
+					break;
+				case 'sgjobs_jobteaser':
+					$event->setPreviewContent(
+						$this->previewService->getTeaserView($record)->render('JobTeaser')
+					);
+					break;
+			}
+		}
+	}
+}
diff --git a/Classes/Hooks/PageLayoutView/PluginRenderer.php b/Classes/Hooks/PageLayoutView/PluginRenderer.php
deleted file mode 100644
index 95186eb4..00000000
--- a/Classes/Hooks/PageLayoutView/PluginRenderer.php
+++ /dev/null
@@ -1,122 +0,0 @@
-<?php
-
-/***************************************************************
- *  Copyright notice
- *  (c) sgalinski Internet Services (https://www.sgalinski.de)
- *  All rights reserved
- *  This script is part of the TYPO3 project. The TYPO3 project is
- *  free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *  The GNU General Public License can be found at
- *  http://www.gnu.org/copyleft/gpl.html.
- *  This script is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
-
-namespace SGalinski\SgJobs\Hooks\PageLayoutView;
-
-use SGalinski\SgJobs\Preview\PreviewService;
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Backend\View\PageLayoutView;
-use TYPO3\CMS\Core\Localization\LanguageService;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * Class PluginRenderer - Renders backend previews for plugins.
- *
- * @package SGalinski\SgJobs\Hooks\PageLayoutView
- */
-class PluginRenderer implements \TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface {
-	/**
-	 * @var PreviewService $previewService
-	 */
-	protected $previewService;
-
-	public function init() {
-		$this->previewService = GeneralUtility::makeInstance(PreviewService::class);
-	}
-
-	/**
-	 * @inheritDoc
-	 * @noinspection ReferencingObjectsInspection
-	 */
-	public function preProcess(
-		PageLayoutView &$parentObject,
-		&$drawItem,
-		&$headerContent,
-		&$itemContent,
-		array &$row
-	): void {
-		$this->init();
-		switch ($row['list_type']) {
-			case 'sgjobs_jobapplication':
-				$drawItem = FALSE;
-				$this->adaptPluginHeaderContent($headerContent, $row);
-
-				$view = $this->previewService->getApplicationView($row);
-				$itemContent .= $view->render();
-				break;
-
-			case 'sgjobs_joblist':
-				$drawItem = FALSE;
-				$this->adaptPluginHeaderContent($headerContent, $row);
-
-				$view = $this->previewService->getJoblistView($row);
-
-				$itemContent .= $view->render();
-				break;
-
-			case 'sgjobs_jobteaser':
-				$drawItem = FALSE;
-				$this->adaptPluginHeaderContent($headerContent, $row);
-
-				$view = $this->previewService->getTeaserView($row);
-				$itemContent .= $view->render();
-				break;
-
-			default:
-				// No need to do anything
-		}
-	}
-
-	/**
-	 * Adapts the given $headerContent.
-	 * To be used in all plugin previews so the Header Contents appear similarly.
-	 *
-	 * @param string $headerContent
-	 * @param array $row
-	 */
-	protected function adaptPluginHeaderContent(&$headerContent, $row): void {
-		$headerContent = '<h4>' . $this->getPluginNameForHeaderContent(
-			(int) $row['pid'],
-			$row['list_type']
-		) . $headerContent . '</h4>';
-	}
-
-	/**
-	 * Finds the label of the given $listType element on the page with the given $pid
-	 * and returns it wrapped for use in the backend preview's header content.
-	 *
-	 * @param int $pid
-	 * @param string $listType
-	 * @return string
-	 */
-	protected function getPluginNameForHeaderContent(int $pid, string $listType): string {
-		$languageService = GeneralUtility::makeInstance(LanguageService::class);
-
-		$pluginName = $languageService->sL(
-			BackendUtility::getLabelFromItemListMerged(
-				$pid,
-				'tt_content',
-				'list_type',
-				$listType
-			)
-		);
-		return '<span class="label label-primary">' . $pluginName . '</span>&nbsp;';
-	}
-}
diff --git a/Classes/Preview/PreviewRenderer.php b/Classes/Preview/PreviewRenderer.php
deleted file mode 100644
index 73c643c4..00000000
--- a/Classes/Preview/PreviewRenderer.php
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-
-/***************************************************************
- *  Copyright notice
- *  (c) sgalinski Internet Services (https://www.sgalinski.de)
- *  All rights reserved
- *  This script is part of the TYPO3 project. The TYPO3 project is
- *  free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *  The GNU General Public License can be found at
- *  http://www.gnu.org/copyleft/gpl.html.
- *  This script is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
-
-namespace SGalinski\SgJobs\Preview;
-
-use TYPO3\CMS\Backend\Preview\PreviewRendererInterface;
-use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
-use TYPO3\CMS\Core\Localization\LanguageService;
-
-/**
- *
- */
-class PreviewRenderer implements PreviewRendererInterface {
-	/**
-	 * @var LanguageService $languageService
-	 */
-	protected $languageService;
-
-	/**
-	 * @var PreviewService $previewService
-	 */
-	protected $previewService;
-
-	public function __construct(LanguageService $languageService, PreviewService $previewService) {
-		$this->languageService = $languageService;
-		$this->previewService = $previewService;
-	}
-
-	/**
-	 * Dedicated method for rendering preview header HTML for
-	 * the page module only. Receives $item which is an instance of
-	 * GridColumnItem which has a getter method to return the record.
-	 *
-	 * @param GridColumnItem $item
-	 * @return string
-	 */
-	public function renderPageModulePreviewHeader(GridColumnItem $item): string {
-		// @todo: when v12 hits, add header from PluginRenderer
-		return '';
-	}
-
-	/**
-	 * Dedicated method for rendering preview body HTML for
-	 * the page module only.
-	 *
-	 * @param GridColumnItem $item
-	 * @return string
-	 */
-	public function renderPageModulePreviewContent(GridColumnItem $item): string {
-		$row = $item->getRecord();
-		switch ($row['list_type']) {
-			case 'sgjobs_jobapplication':
-				$view = $this->previewService->getApplicationView($row);
-				return $view->render();
-
-			case 'sgjobs_joblist':
-				$view = $this->previewService->getJoblistView($row);
-				return $view->render();
-
-			case 'sgjobs_jobteaser':
-				$view = $this->previewService->getTeaserView($row);
-				return $view->render();
-
-			default:
-				// No need to do anything
-		}
-
-		return '';
-	}
-
-	/**
-	 * Render a footer for the record to display in page module below
-	 * the body of the item's preview.
-	 *
-	 * @param GridColumnItem $item
-	 * @return string
-	 */
-	public function renderPageModulePreviewFooter(GridColumnItem $item): string {
-		return '';
-	}
-
-	/**
-	 * Dedicated method for wrapping a preview header and body HTML.
-	 *
-	 * @param string $previewHeader
-	 * @param string $previewContent
-	 * @param GridColumnItem $item
-	 * @return string
-	 */
-	public function wrapPageModulePreview(string $previewHeader, string $previewContent, GridColumnItem $item): string {
-		return $previewHeader . $previewContent;
-	}
-}
diff --git a/Classes/Preview/PreviewService.php b/Classes/Preview/PreviewService.php
index 9d3371fb..70ea10e4 100644
--- a/Classes/Preview/PreviewService.php
+++ b/Classes/Preview/PreviewService.php
@@ -43,7 +43,7 @@ class PreviewService {
 	 * @return StandaloneView
 	 */
 	public function getApplicationView(array $row): StandaloneView {
-		$view = $this->createViewWithTemplate('JobApplication');
+		$view = $this->createView();
 		$view->assign('uid', $row['uid']);
 
 		// Get available plugin settings and their values from flexform
@@ -62,6 +62,12 @@ class PreviewService {
 		];
 
 		$view->assign('data', $templateData);
+		$view->assign('headerLabel', BackendUtility::getLabelFromItemListMerged(
+			$row['pid'],
+			'tt_content',
+			'list_type',
+			$row['list_type']
+		));
 		return $view;
 	}
 
@@ -72,7 +78,7 @@ class PreviewService {
 	 * @return StandaloneView
 	 */
 	public function getJoblistView(array $row): StandaloneView {
-		$view = $this->createViewWithTemplate('Joblist');
+		$view = $this->createView();
 		$view->assign('uid', $row['uid']);
 
 		// Get available plugin settings and their values from flexform
@@ -113,11 +119,17 @@ class PreviewService {
 			) : ''
 		);
 		$view->assign('recursive', $row['recursive']);
+		$view->assign('headerLabel', BackendUtility::getLabelFromItemListMerged(
+			$row['pid'],
+			'tt_content',
+			'list_type',
+			$row['list_type']
+		));
 		return $view;
 	}
 
 	public function getTeaserView(array $row): StandaloneView {
-		$view = $this->createViewWithTemplate('JobTeaser');
+		$view = $this->createView();
 		$view->assign('uid', $row['uid']);
 
 		// Get available plugin settings and their values from flexform
@@ -146,6 +158,12 @@ class PreviewService {
 		];
 
 		$view->assign('data', $templateData);
+		$view->assign('headerLabel', BackendUtility::getLabelFromItemListMerged(
+			$row['pid'],
+			'tt_content',
+			'list_type',
+			$row['list_type']
+		));
 		return $view;
 	}
 
@@ -172,18 +190,13 @@ class PreviewService {
 	 * Creates a new StandaloneView object with template and partial root paths,
 	 * attaches the template with the given name to it and returns it.
 	 *
-	 * @param string $templateName
 	 * @return StandaloneView
 	 */
-	protected function createViewWithTemplate(string $templateName): StandaloneView {
+	protected function createView(): StandaloneView {
 		$view = GeneralUtility::makeInstance(StandaloneView::class);
 		$view->setTemplateRootPaths(['EXT:sg_jobs/Resources/Private/Backend/Templates/']);
 		$view->setPartialRootPaths(['EXT:sg_jobs/Resources/Private/Backend/Partials/']);
 		$view->setLayoutRootPaths(['EXT:sg_jobs/Resources/Private/Backend/Layouts/']);
-		if (!str_ends_with($templateName, '.html')) {
-			$templateName .= '.html';
-		}
-		$view->setTemplate($templateName);
 		return $view;
 	}
 
@@ -214,6 +227,7 @@ class PreviewService {
 
 			$recordsWithTitlesArray[] = $record[$field] . ' [' . $recordId . ']';
 		}
+
 		return implode(', ', $recordsWithTitlesArray);
 	}
 }
diff --git a/Classes/Updates/DepartmentUpdateWizard.php b/Classes/Updates/DepartmentUpdateWizard.php
deleted file mode 100644
index 37b60f97..00000000
--- a/Classes/Updates/DepartmentUpdateWizard.php
+++ /dev/null
@@ -1,226 +0,0 @@
-<?php
-
-/**
- * Copyright notice
- *
- * (c) sgalinski Internet Services (https://www.sgalinski.de)
- *
- * All rights reserved
- *
- * This script is part of the TYPO3 project. The TYPO3 project is
- * free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * The GNU General Public License can be found at
- * http://www.gnu.org/copyleft/gpl.html.
- *
- * This script is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This copyright notice MUST APPEAR in all copies of the script!
- */
-
-namespace SGalinski\SgJobs\Updates;
-
-use TYPO3\CMS\Core\Database\Connection;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite;
-use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
-
-/**
- * Class DepartmentUpdateWizard
- */
-class DepartmentUpdateWizard implements UpgradeWizardInterface {
-	/**
-	 * The wizard identifier
-	 */
-	public const IDENTIFIER = 'tx_sgjobs_departmentupdatewizward';
-
-	/**
-	 * Check if the job table has a deleted area field
-	 *
-	 * @return bool
-	 */
-	protected function hasDeletedAreaField(): bool {
-		return $this->hasField('zzz_deleted_area');
-	}
-
-	/**
-	 * Check if the job table has an area field
-	 *
-	 * @return bool
-	 */
-	protected function hasAreaField(): bool {
-		return $this->hasField('area');
-	}
-
-	/**
-	 * Check if the job database table has a field with the given name in it
-	 *
-	 * @param string $fieldName
-	 * @return bool
-	 */
-	protected function hasField(string $fieldName): bool {
-		$connection = $this->getDatabaseConnection();
-		$tableColumns = $connection->getSchemaManager()->listTableColumns('tx_sgjobs_domain_model_job');
-		if (\array_key_exists($fieldName, $tableColumns)) {
-			return TRUE;
-		}
-		return FALSE;
-	}
-
-	/**
-	 * Get the database query builder
-	 *
-	 * @return Connection
-	 */
-	protected function getDatabaseConnection(): Connection {
-		$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
-		return $connectionPool->getConnectionForTable('tx_sgjobs_domain_model_job');
-	}
-
-	/**
-	 * @return string
-	 */
-	public function getIdentifier(): string {
-		return self::IDENTIFIER;
-	}
-
-	/**
-	 * @return string
-	 */
-	public function getTitle(): string {
-		return 'Migrate old fulltext job areas to department records';
-	}
-
-	/**
-	 * @return string
-	 */
-	public function getDescription(): string {
-		return '';
-	}
-
-	/**
-	 * @return bool
-	 */
-	public function executeUpdate(): bool {
-		$connection = $this->getDatabaseConnection();
-		$queryBuilder = $connection->createQueryBuilder();
-		$field = $this->hasDeletedAreaField() ? 'zzz_deleted_area' : 'area';
-		$queryBuilder->getRestrictions()->removeAll();
-		/**
-		 * @var array $jobs
-		 */
-		$jobs = $queryBuilder->select('uid', 'pid', 'sys_language_uid', $field)
-			->from('tx_sgjobs_domain_model_job')
-			->execute()
-			->fetchAll();
-
-		$newDepartments = [];
-		if (\count($jobs) > 0) {
-			foreach ($jobs as $index => $job) {
-				if ($job[$field]) {
-					$identifier = $job[$field] . '-' . $job['pid'] . '-' . $job['sys_language_uid'];
-					$newDepartments[$identifier] = [
-						'title' => $job[$field],
-						'pid' => $job['pid'],
-						'sys_language_uid' => $job['sys_language_uid']
-					];
-				} else {
-					unset($jobs[$index]);
-				}
-			}
-
-			if (\count($jobs) > 0) {
-				\array_walk(
-					$newDepartments,
-					function ($department) use (&$dbQueries, $connection) {
-						$queryBuilder = $connection->createQueryBuilder();
-						$queryBuilder->insert('tx_sgjobs_domain_model_department')->values($department)->execute();
-						$dbQueries[] = $queryBuilder->getSQL();
-					}
-				);
-
-				$queryBuilder = $connection->createQueryBuilder();
-				$departments = $queryBuilder->select('uid', 'pid', 'sys_language_uid', 'title')
-					->from('tx_sgjobs_domain_model_department')
-					->execute()
-					->fetchAll();
-
-				$identifiedDepartments = [];
-				foreach ($departments as $department) {
-					$identifier = $department['title'] . '-' . $department['pid'] . '-' . $department['sys_language_uid'];
-					$identifiedDepartments[$identifier] = $department;
-				}
-
-				$dbQueries[] = $queryBuilder->getSQL();
-
-				foreach ($jobs as $index => $job) {
-					$identifier = $job[$field] . '-' . $job['pid'] . '-' . $job['sys_language_uid'];
-					if (isset($identifiedDepartments[$identifier])) {
-						$jobs[$index]['department'] = $identifiedDepartments[$identifier]['uid'];
-						unset($jobs[$index][$field]);
-					} else {
-						unset($jobs[$index]);
-					}
-				}
-
-				if (\count($jobs) > 0) {
-					\array_walk(
-						$jobs,
-						function ($job) use ($connection) {
-							$queryBuilder = $connection->createQueryBuilder();
-							$queryBuilder->update('tx_sgjobs_domain_model_job')
-								->set('department', (int) $job['department'])
-								->where(
-									$queryBuilder->expr()->eq(
-										'uid',
-										$queryBuilder->createNamedParameter($job['uid'], \PDO::PARAM_INT)
-									)
-								)->execute();
-						}
-					);
-				}
-			}
-		}
-
-		return TRUE;
-	}
-
-	/**
-	 * @return bool
-	 */
-	public function updateNecessary(): bool {
-		if (
-			!GeneralUtility::makeInstance(ConnectionPool::class)
-				->getConnectionForTable('tx_sgjobs_domain_model_department')
-				->getSchemaManager()
-				->tablesExist(['tx_sgjobs_domain_model_department'])
-		) {
-			return FALSE;
-		}
-
-		if (
-			$this->hasAreaField() ||
-			$this->hasDeletedAreaField()
-		) {
-			return TRUE;
-		}
-
-		return FALSE;
-	}
-
-	/**
-	 * @return array|string[]
-	 */
-	public function getPrerequisites(): array {
-		return [
-			DatabaseUpdatedPrerequisite::class
-		];
-	}
-}
diff --git a/Configuration/Backend/Modules.php b/Configuration/Backend/Modules.php
new file mode 100644
index 00000000..19e49d51
--- /dev/null
+++ b/Configuration/Backend/Modules.php
@@ -0,0 +1,19 @@
+<?php
+
+use SGalinski\SgJobs\Controller\BackendController;
+
+return [
+	'web_SgJobs_backend' => [
+		'parent' => 'web',
+		'position' => ['after' => ''],
+		'access' => 'user,group',
+		'workspaces' => 'live',
+		'path' => '/module/web/sg_jobs_backend',
+		'labels' => 'LLL:EXT:sg_jobs/Resources/Private/Language/locallang_backend.xlf',
+		'iconIdentifier' => 'extension-sg_jobs-module',
+		'extensionName' => 'SgJobs',
+		'controllerActions' => [
+			BackendController::class => ['index']
+		]
+	]
+];
diff --git a/Configuration/Services.php b/Configuration/Services.php
index eff1747f..ae604c7d 100644
--- a/Configuration/Services.php
+++ b/Configuration/Services.php
@@ -25,10 +25,11 @@
 
 use SGalinski\SgJobs\Event\Listener\AccessPageListEventListener;
 use SGalinski\SgJobs\Event\Listener\ExcludeFromReferenceIndexListener;
-use SGalinski\SgJobs\Preview\PreviewRenderer;
+use SGalinski\SgJobs\EventListeners\PageContentPreviewRenderingEventListener;
 use SGalinski\SgJobs\Service\BackendService;
 use SGalinski\SgJobs\Service\SitemapService;
 use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+use TYPO3\CMS\Backend\View\Event\PageContentPreviewRenderingEvent;
 use TYPO3\CMS\Core\DataHandling\Event\IsTableExcludedFromReferenceIndexEvent;
 
 return static function (ContainerConfigurator $containerConfigurator): void {
@@ -41,7 +42,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
 
 	$services->set(SitemapService::class)->public();
 	$services->set(BackendService::class)->public();
-	$services->set(PreviewRenderer::class)->public();
 
 	if (class_exists('\SGalinski\SgSeo\Events\AccessPageListEvent')) {
 		$services->set(AccessPageListEventListener::class)
@@ -56,4 +56,9 @@ return static function (ContainerConfigurator $containerConfigurator): void {
 			'identifier' => 'sg-jobs/excludeFromRefIndex',
 			'event' => IsTableExcludedFromReferenceIndexEvent::class
 		]);
+
+	$services->set(PageContentPreviewRenderingEventListener::class)
+		->tag('event.listener', [
+			'event' => PageContentPreviewRenderingEvent::class
+		]);
 };
diff --git a/Configuration/TCA/tx_sgjobs_domain_model_company.php b/Configuration/TCA/tx_sgjobs_domain_model_company.php
index a5d830d3..6a18d1f2 100644
--- a/Configuration/TCA/tx_sgjobs_domain_model_company.php
+++ b/Configuration/TCA/tx_sgjobs_domain_model_company.php
@@ -45,7 +45,10 @@ $columns = [
 			'endtime' => 'endtime',
 		],
 		'sortby' => 'sorting',
-		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_company.svg'
+		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_company.svg',
+		'security' => [
+			'ignorePageTypeRestriction' => TRUE
+		]
 	],
 	'interface' => [],
 	'types' => [
diff --git a/Configuration/TCA/tx_sgjobs_domain_model_contact.php b/Configuration/TCA/tx_sgjobs_domain_model_contact.php
index 4569f013..994d3c52 100644
--- a/Configuration/TCA/tx_sgjobs_domain_model_contact.php
+++ b/Configuration/TCA/tx_sgjobs_domain_model_contact.php
@@ -47,7 +47,10 @@ $columns = [
 			'endtime' => 'endtime',
 		],
 		'sortby' => 'sorting',
-		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_contact.svg'
+		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_contact.svg',
+		'security' => [
+			'ignorePageTypeRestriction' => TRUE
+		]
 	],
 	'interface' => [],
 	'types' => [
diff --git a/Configuration/TCA/tx_sgjobs_domain_model_department.php b/Configuration/TCA/tx_sgjobs_domain_model_department.php
index 25b1531d..3068419d 100644
--- a/Configuration/TCA/tx_sgjobs_domain_model_department.php
+++ b/Configuration/TCA/tx_sgjobs_domain_model_department.php
@@ -45,7 +45,10 @@ $columns = [
 			'endtime' => 'endtime',
 		],
 		'sortby' => 'sorting',
-		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_department.svg'
+		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_department.svg',
+		'security' => [
+			'ignorePageTypeRestriction' => TRUE
+		]
 	],
 	'interface' => [],
 	'types' => [
diff --git a/Configuration/TCA/tx_sgjobs_domain_model_experience_level.php b/Configuration/TCA/tx_sgjobs_domain_model_experience_level.php
index 2d8beddf..8f7860bb 100644
--- a/Configuration/TCA/tx_sgjobs_domain_model_experience_level.php
+++ b/Configuration/TCA/tx_sgjobs_domain_model_experience_level.php
@@ -45,7 +45,10 @@ $columns = [
 			'endtime' => 'endtime',
 		],
 		'sortby' => 'sorting',
-		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_experience_level.svg'
+		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_experience_level.svg',
+		'security' => [
+			'ignorePageTypeRestriction' => TRUE
+		]
 	],
 	'interface' => [],
 	'types' => [
diff --git a/Configuration/TCA/tx_sgjobs_domain_model_job.php b/Configuration/TCA/tx_sgjobs_domain_model_job.php
index 4f463699..399ea858 100644
--- a/Configuration/TCA/tx_sgjobs_domain_model_job.php
+++ b/Configuration/TCA/tx_sgjobs_domain_model_job.php
@@ -49,7 +49,10 @@ $columns = [
 			'endtime' => 'endtime',
 		],
 		'sortby' => 'sorting',
-		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_job.svg'
+		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_job.svg',
+		'security' => [
+			'ignorePageTypeRestriction' => TRUE
+		]
 	],
 	'interface' => [],
 	'types' => [
diff --git a/Configuration/TCA/tx_sgjobs_domain_model_job_application.php b/Configuration/TCA/tx_sgjobs_domain_model_job_application.php
index 3a76740f..4a0a4991 100644
--- a/Configuration/TCA/tx_sgjobs_domain_model_job_application.php
+++ b/Configuration/TCA/tx_sgjobs_domain_model_job_application.php
@@ -47,7 +47,10 @@ $columns = [
 			'endtime' => 'endtime',
 		],
 		'sortby' => 'sorting',
-		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_job.svg'
+		'iconfile' => 'EXT:sg_jobs/Resources/Public/Icons/tx_sgjobs_domain_model_job.svg',
+		'security' => [
+			'ignorePageTypeRestriction' => TRUE
+		]
 	],
 	'interface' => [],
 	'types' => [
diff --git a/ext_localconf.php b/ext_localconf.php
index 430d0553..33970f02 100644
--- a/ext_localconf.php
+++ b/ext_localconf.php
@@ -50,10 +50,6 @@ call_user_func(
 			]
 		);
 
-		// Backend preview for plugins
-		$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem']['sg_jobs']
-			= \SGalinski\SgJobs\Hooks\PageLayoutView\PluginRenderer::class;
-
 		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTypoScriptConstants(
 			'@import "EXT:sg_jobs/Configuration/TypoScript/Backend/constants.typoscript"'
 		);
@@ -66,10 +62,6 @@ call_user_func(
 		$GLOBALS['sg_mail']['sg_jobs']['ApplicationMail'] = 'EXT:sg_jobs/Configuration/SgMail/ApplicationMail.php';
 		$GLOBALS['sg_mail']['sg_jobs']['ApplicantMail'] = 'EXT:sg_jobs/Configuration/SgMail/ApplicantMail.php';
 
-		// Register the upgrade wizard
-		$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update'][\SGalinski\SgJobs\Updates\DepartmentUpdateWizard::IDENTIFIER]
-			= \SGalinski\SgJobs\Updates\DepartmentUpdateWizard::class;
-
 		//include Plugin sg_jobs
 		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
 			'@import "EXT:sg_jobs/Configuration/TsConfig/Page/NewContentElementWizard.tsconfig"'
diff --git a/ext_tables.php b/ext_tables.php
deleted file mode 100644
index b6a52756..00000000
--- a/ext_tables.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-
-call_user_func(
-	static function () {
-		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages(
-			'tx_sgjobs_domain_model_job'
-		);
-		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages(
-			'tx_sgjobs_domain_model_contact'
-		);
-		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages(
-			'tx_sgjobs_domain_model_company'
-		);
-		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages(
-			'tx_sgjobs_domain_model_job_application'
-		);
-		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages(
-			'tx_sgjobs_domain_model_department'
-		);
-		\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages(
-			'tx_sgjobs_domain_model_experience_level'
-		);
-
-		// Register backend modules
-		\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
-			'SgJobs',
-			'web',
-			'Backend',
-			'',
-			[
-				\SGalinski\SgJobs\Controller\BackendController::class => 'index',
-			],
-			[
-				'access' => 'user,group',
-				'iconIdentifier' => 'extension-sg_jobs-module',
-				'labels' => 'LLL:EXT:sg_jobs/Resources/Private/Language/locallang_backend.xlf',
-			]
-		);
-	}
-);
-- 
GitLab