From 38b4844a9dc5f4af1d46ce43d7a15748c05b9278 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Mon, 11 Jan 2021 09:20:51 +0100 Subject: [PATCH] Add pages to events Allow editor to reference TYPO3 page records from events. E.g. used to provide further internal information links. Also those pages are resolved via DataProcessing. That allows integrators to be 100% flexible to resolve those page info. By default a menu is generated and media is resolved. Also validation is ignored, as this improves performance and allows to use the new class as injected property without validation fails. Models are not managed via frontend and therefore don't need validation. Relates: #8092 --- Classes/Controller/DateController.php | 18 ++ Classes/Controller/EventController.php | 18 ++ Classes/Domain/Model/Event.php | 32 ++- Classes/Service/DataProcessingForModels.php | 176 ++++++++++++ .../TCA/tx_events_domain_model_event.php | 15 +- Configuration/TypoScript/setup.typoscript | 15 ++ .../Language/de.locallang_csh_event.xlf | 254 +++++++++--------- .../Private/Language/locallang_csh_event.xlf | 187 ++++++------- ext_tables.sql | 1 + 9 files changed, 495 insertions(+), 221 deletions(-) create mode 100644 Classes/Service/DataProcessingForModels.php diff --git a/Classes/Controller/DateController.php b/Classes/Controller/DateController.php index b83e882..1a55ec9 100644 --- a/Classes/Controller/DateController.php +++ b/Classes/Controller/DateController.php @@ -4,6 +4,7 @@ namespace Wrm\Events\Controller; use TYPO3\CMS\Core\Database\QueryGenerator; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Annotation as Extbase; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use Wrm\Events\Domain\Model\Date; @@ -11,6 +12,7 @@ use Wrm\Events\Domain\Model\Dto\DateDemand; use Wrm\Events\Domain\Repository\CategoryRepository; use Wrm\Events\Domain\Repository\DateRepository; use Wrm\Events\Domain\Repository\RegionRepository; +use Wrm\Events\Service\DataProcessingForModels; /** * DateController @@ -38,6 +40,11 @@ class DateController extends ActionController */ protected $queryGenerator; + /** + * @var DataProcessingForModels + */ + protected $dataProcessing; + /** * @var array */ @@ -58,11 +65,20 @@ class DateController extends ActionController $this->categoryRepository = $categoryRepository; } + /** + * @param DataProcessingForModels $dataProcessing + */ + public function injectDataProcessingForModels(DataProcessingForModels $dataProcessing) + { + $this->dataProcessing = $dataProcessing; + } + /** * Action initializer */ protected function initializeAction() { + $this->dataProcessing->setConfigurationManager($this->configurationManager); $this->pluginSettings = $this->configurationManager->getConfiguration( ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK ); @@ -126,6 +142,8 @@ class DateController extends ActionController /** * action show * + * @Extbase\IgnoreValidation("date") + * * @param \Wrm\Events\Domain\Model\Date $date * @return void */ diff --git a/Classes/Controller/EventController.php b/Classes/Controller/EventController.php index 987f466..9c2e591 100644 --- a/Classes/Controller/EventController.php +++ b/Classes/Controller/EventController.php @@ -3,11 +3,13 @@ namespace Wrm\Events\Controller; use TYPO3\CMS\Core\Database\QueryGenerator; +use TYPO3\CMS\Extbase\Annotation as Extbase; use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use Wrm\Events\Domain\Model\Dto\EventDemand; use Wrm\Events\Domain\Model\Event; use Wrm\Events\Domain\Repository\EventRepository; +use Wrm\Events\Service\DataProcessingForModels; /** * EventController @@ -26,6 +28,11 @@ class EventController extends ActionController */ protected $queryGenerator; + /** + * @var DataProcessingForModels + */ + protected $dataProcessing; + /** * @var array */ @@ -39,11 +46,20 @@ class EventController extends ActionController $this->eventRepository = $eventRepository; } + /** + * @param DataProcessingForModels $dataProcessing + */ + public function injectDataProcessingForModels(DataProcessingForModels $dataProcessing) + { + $this->dataProcessing = $dataProcessing; + } + /** * Action initializer */ protected function initializeAction() { + $this->dataProcessing->setConfigurationManager($this->configurationManager); $this->pluginSettings = $this->configurationManager->getConfiguration( ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK ); @@ -65,6 +81,8 @@ class EventController extends ActionController /** * Action show * + * @Extbase\IgnoreValidation("event") + * * @param Event $event * @return void */ diff --git a/Classes/Domain/Model/Event.php b/Classes/Domain/Model/Event.php index 24bd30f..d3ee979 100644 --- a/Classes/Domain/Model/Event.php +++ b/Classes/Domain/Model/Event.php @@ -2,7 +2,6 @@ namespace Wrm\Events\Domain\Model; -use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Annotation as Extbase; use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; use TYPO3\CMS\Extbase\Domain\Model\Category; @@ -10,6 +9,7 @@ use TYPO3\CMS\Extbase\Domain\Model\FileReference; use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Persistence\ObjectStorage; use Wrm\Events\Domain\Repository\DateRepository; +use Wrm\Events\Service\DataProcessingForModels; /** * Event @@ -194,6 +194,11 @@ class Event extends AbstractEntity */ protected $region = null; + /** + * @var string + */ + protected $pages = ''; + /** * categories * @@ -206,6 +211,11 @@ class Event extends AbstractEntity */ protected $_languageUid; + /** + * @var DataProcessingForModels + */ + private $dataProcessing = null; + /** * __construct */ @@ -216,6 +226,14 @@ class Event extends AbstractEntity $this->initStorageObjects(); } + /** + * @param DataProcessingForModels $dataProcessing + */ + public function injectDataProcessingForModels(DataProcessingForModels $dataProcessing) + { + $this->dataProcessing = $dataProcessing; + } + /** * @return void */ @@ -688,6 +706,18 @@ class Event extends AbstractEntity $this->country = $country; } + public function getPages(): array + { + static $pages = null; + if (is_array($pages)) { + return $pages; + } + + $pages = $this->dataProcessing->process($this); + + return $pages; + } + /** * @param \TYPO3\CMS\Extbase\Domain\Model\Category<\TYPO3\CMS\Extbase\Domain\Model\Category> $category */ diff --git a/Classes/Service/DataProcessingForModels.php b/Classes/Service/DataProcessingForModels.php new file mode 100644 index 0000000..bc5a596 --- /dev/null +++ b/Classes/Service/DataProcessingForModels.php @@ -0,0 +1,176 @@ + + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +use TYPO3\CMS\Core\Database\Connection; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\SingletonInterface; +use TYPO3\CMS\Core\TypoScript\TypoScriptService; +use TYPO3\CMS\Core\Utility\ArrayUtility; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; +use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; +use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory; +use TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor; +use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; + +/** + * Used by models to apply data processing. + * This allows for flexibility of integrators. + * + * E.g. pages are saved for each event. + * An integrator now can resolve them via data processing to arrays or menus. + * + * dataProcessing is configured via TypoScript for each plugin or whole extension via + * settings.dataProcessing.fqcn, e.g.: + * + * plugin.tx_events { + * settings { + * dataProcessing { + * Wrm\Events\Domain\Model\Event { + * 10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor + * 10 { + * special = list + * special.value.field = pages + * dataProcessing { + * 10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor + * 10 { + * references.fieldName = media + * } + * } + * } + * } + * } + * } + * } + * + * Currently supported by: + * + * - Event->getPages() + */ +class DataProcessingForModels implements SingletonInterface +{ + /** + * @var ContentObjectRenderer + */ + private $cObject; + + /** + * @var ContentDataProcessor + */ + private $processorHandler; + + /** + * @var Connection + */ + private $connection; + + /** + * @var DataMapFactory + */ + private $dataMapFactory; + + /** + * @var ConfigurationManagerInterface|null + */ + private $configurationManager; + + /** + * @var TypoScriptService + */ + private $typoScriptService; + + public function __construct( + ContentDataProcessor $processorHandler, + ConnectionPool $connectionPool, + DataMapFactory $dataMapFactory, + TypoScriptService $typoScriptService + ) { + $this->cObject = GeneralUtility::makeInstance(ContentObjectRenderer::class); + $this->processorHandler = $processorHandler; + $this->connection = $connectionPool->getConnectionByName('Default'); + $this->dataMapFactory = $dataMapFactory; + $this->typoScriptService = $typoScriptService; + } + + /** + * Used to set current configuration from within plugin. + * + * Inject and call this method, e.g. within initializeAction. + * Necessary to get plugin configuration containing dataProcessing configuration. + */ + public function setConfigurationManager(ConfigurationManagerInterface $configurationManager): void + { + $this->configurationManager = $configurationManager; + } + + public function process( + AbstractEntity $entity + ): array { + $configuration = $this->getConfiguration($entity); + + if ($configuration === []) { + return []; + } + + $this->cObject->start($this->getData($entity), $this->getTable($entity)); + return $this->processorHandler->process($this->cObject, $configuration, []); + } + + private function getData(AbstractEntity $entity): array + { + $row = $this->connection->select(['*'], $this->getTable($entity), ['uid' => $entity->getUid()])->fetch(); + if (is_array($row)) { + return $row; + } + + return []; + } + + private function getTable(AbstractEntity $entity): string + { + $dataMap = $this->dataMapFactory->buildDataMap(get_class($entity)); + return $dataMap->getTableName(); + } + + private function getConfiguration(AbstractEntity $entity): array + { + if ($this->configurationManager === null) { + return []; + } + + $className = get_class($entity); + $settings = $this->configurationManager->getConfiguration( + ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS + ); + + if (ArrayUtility::isValidPath($settings, 'dataProcessing.' . $className, '.') === false) { + return []; + } + + $configuration = ArrayUtility::getValueByPath($settings, 'dataProcessing.' . $className, '.'); + $configuration = $this->typoScriptService->convertPlainArrayToTypoScriptArray($configuration); + return [ + 'dataProcessing.' => $configuration, + ]; + } +} diff --git a/Configuration/TCA/tx_events_domain_model_event.php b/Configuration/TCA/tx_events_domain_model_event.php index 4cdff31..32ac676 100644 --- a/Configuration/TCA/tx_events_domain_model_event.php +++ b/Configuration/TCA/tx_events_domain_model_event.php @@ -20,7 +20,7 @@ return [ 'iconfile' => 'EXT:events/Resources/Public/Icons/tx_events_domain_model_event.gif' ], 'types' => [ - '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, title, global_id, slug, highlight, teaser, details, price_info, name, street, district, city, zip, country, phone, web, ticket, facebook, youtube, instagram, latitude, longitude, images, categories, dates, organizer, region, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, title, global_id, slug, highlight, teaser, details, price_info, name, street, district, city, zip, country, phone, web, ticket, facebook, youtube, instagram, latitude, longitude, images, pages, categories, dates, organizer, region, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], ], 'columns' => [ 'sys_language_uid' => [ @@ -185,7 +185,7 @@ return [ 'rows' => 15, 'eval' => 'trim', ], - + ], 'price_info' => [ 'exclude' => true, @@ -379,6 +379,16 @@ return [ ), ], + 'pages' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_event.xlf:tx_events_domain_model_event.pages', + 'config' => [ + 'type' => 'group', + 'internal_type' => 'db', + 'allowed' => 'pages', + ], + ], + 'categories' => [ 'exclude' => true, 'label' => 'LLL:EXT:events/Resources/Private/Language/locallang_csh_event.xlf:tx_events_domain_model_event.categories', @@ -443,6 +453,5 @@ return [ 'maxitems' => 1, ], ], - ], ]; diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 46197a6..71c4f8c 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -56,6 +56,21 @@ plugin.tx_events { categoriesPid = {$plugin.tx_events.settings.destinationData.categoriesPid} categoryParentUid = {$plugin.tx_events.settings.destinationData.categoryParentUid} } + dataProcessing { + Wrm\Events\Domain\Model\Event { + 10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor + 10 { + special = list + special.value.field = pages + dataProcessing { + 10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor + 10 { + references.fieldName = media + } + } + } + } + } } } diff --git a/Resources/Private/Language/de.locallang_csh_event.xlf b/Resources/Private/Language/de.locallang_csh_event.xlf index 0b8d472..5f157c9 100644 --- a/Resources/Private/Language/de.locallang_csh_event.xlf +++ b/Resources/Private/Language/de.locallang_csh_event.xlf @@ -1,128 +1,132 @@ - -
- - - Events - Veranstaltungen - - - Event Modul - Veranstaltungs Modul - - - Event - Veranstaltung - - - Title - Titel - - - Global UID - Globale UID - - - Slug - URL-Segment - - - Highlight - Höhepunkt - - - Teaser - Kurztext - - - Details - Text - - - Price Info - Preis Information - - - Name - Name - - - Street - Straße - - - District - Bundesland - - - City - Stadt - - - Zip - Postleitzahl - - - Country - Land - - - Web - Internet - - - Phone - Telefon - - - Ticket - Ticket - - - Facebook - Facebook - - - YouTube - YouTube - - - Instagram - Instagram - - - Latitude - Breitengrad - - - Longitude - Längengrad - - - Images - Bilder - - - Categories - Kategorien - - - Dates - Termine - - - Organizer - Organisator - - - Region - Region - - - Organizer - Organisator - - - + +
+ + + Events + Veranstaltungen + + + Event Modul + Veranstaltungs Modul + + + Event + Veranstaltung + + + Title + Titel + + + Global UID + Globale UID + + + Slug + URL-Segment + + + Highlight + Höhepunkt + + + Teaser + Kurztext + + + Details + Text + + + Price Info + Preis Information + + + Name + Name + + + Street + Straße + + + District + Bundesland + + + City + Stadt + + + Zip + Postleitzahl + + + Country + Land + + + Web + Internet + + + Phone + Telefon + + + Ticket + Ticket + + + Facebook + Facebook + + + YouTube + YouTube + + + Instagram + Instagram + + + Latitude + Breitengrad + + + Longitude + Längengrad + + + Images + Bilder + + + Pages + Seiten + + + Categories + Kategorien + + + Dates + Termine + + + Organizer + Organisator + + + Region + Region + + + Organizer + Organisator + + + diff --git a/Resources/Private/Language/locallang_csh_event.xlf b/Resources/Private/Language/locallang_csh_event.xlf index 6608918..7f781ba 100644 --- a/Resources/Private/Language/locallang_csh_event.xlf +++ b/Resources/Private/Language/locallang_csh_event.xlf @@ -1,95 +1,98 @@ - -
- - - Events - - - Event Modul - - - Event - - - Title - - - Global UID - - - Slug - - - Highlight - - - Teaser - - - Details - - - Price Info - - - Name - - - Street - - - District - - - City - - - Zip - - - Country - - - Web - - - Phone - - - Ticket - - - Facebook - - - Youtube - - - Instagram - - - Latitude - - - Longitude - - - Images - - - Categories - - - Dates - - - Organizer - - - Region - - - + +
+ + + Events + + + Event Modul + + + Event + + + Title + + + Global UID + + + Slug + + + Highlight + + + Teaser + + + Details + + + Price Info + + + Name + + + Street + + + District + + + City + + + Zip + + + Country + + + Web + + + Phone + + + Ticket + + + Facebook + + + Youtube + + + Instagram + + + Latitude + + + Longitude + + + Images + + + Pages + + + Categories + + + Dates + + + Organizer + + + Region + + + diff --git a/ext_tables.sql b/ext_tables.sql index d2b48a6..29ed630 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -26,6 +26,7 @@ CREATE TABLE tx_events_domain_model_event ( longitude varchar(255) DEFAULT '' NOT NULL, images int(11) unsigned NOT NULL default '0', categories int(11) DEFAULT '0' NOT NULL, + pages text, dates int(11) unsigned DEFAULT '0' NOT NULL, organizer int(11) unsigned DEFAULT '0', region int(11) unsigned DEFAULT '0',