From 94fb7e4c98f2c450d2efc29d5fc1d31b733b741c Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 23 Mar 2022 08:54:23 +0100 Subject: [PATCH 01/56] [BUGFIX] Respect record language when attaching pages to parents Otherwise the parentRecord will not accept the child record because they are not related. Translations must be attached to their translation parent records. --- .../ShallowRecordFinder.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php b/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php index 0e43f400f..78be0e746 100644 --- a/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php +++ b/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php @@ -268,7 +268,19 @@ protected function addChildPagesRecursively(array $pageRecords): array $rows = $this->dualDatabaseRepository->findMissingRows('pages', $rows); $setParentRecord = static function (RecordInterface $record) use (&$pageRecords): void { - $pid = $record->getLocalProperty('pid') ?? $record->getForeignProperty('pid'); + $languageField = $GLOBALS['TCA']['pages']['ctrl']['languageField'] ?? null; + if (null !== $languageField) { + $language = $record->getLocalProperty($languageField) ?? $record->getForeignProperty($languageField); + if ($language > 0) { + $transOrigPointerField = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'] ?? null; + if (null !== $transOrigPointerField) { + $pid = $record->getLocalProperty($transOrigPointerField) ?? $record->getForeignProperty($transOrigPointerField); + } + } + } + if (empty($pid)) { + $pid = $record->getLocalProperty('pid') ?? $record->getForeignProperty('pid'); + } $pageRecords[$record->getIdentifier()] = $record; $pageRecords[$pid]->addRelatedRecord($record); }; From ff4a5d430cc77f15a4415f195aff73d56727bd7f Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 23 Mar 2022 09:04:32 +0100 Subject: [PATCH 02/56] [BUGFIX] Set start depth to 1 for the SimplifiedOverviewAndPublishing root record --- .../SimplifiedOverviewAndPublishing/ShallowRecordFinder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php b/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php index 78be0e746..486f06192 100644 --- a/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php +++ b/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php @@ -131,7 +131,7 @@ protected function findPageRecord(int $identifier, bool $excludePages): RecordIn $rows = $this->dualDatabaseRepository->findByProperty('pages', 'uid', [$identifier]); $rowSet = $rows[$identifier]; } - $rowSet['additional'] = ['depth' => 0, 'isRoot' => true]; + $rowSet['additional'] = ['depth' => 1, 'isRoot' => true]; $this->createRecord( 'pages', $rowSet, From 862bc48a20b39079f84f3dd29e9f28a97cd4827f Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 5 Apr 2022 11:18:33 +0200 Subject: [PATCH 03/56] [BUGFIX] Always preprend the eventListener for the publishing confirmation Related: https://projekte.in2code.de/issues/50088 --- Resources/Public/JavaScript/BackendModule.js | 44 +++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/Resources/Public/JavaScript/BackendModule.js b/Resources/Public/JavaScript/BackendModule.js index 86ac3c087..1c557e9dd 100644 --- a/Resources/Public/JavaScript/BackendModule.js +++ b/Resources/Public/JavaScript/BackendModule.js @@ -124,24 +124,36 @@ define([ }; In2publishModule.overlayListener = function () { - $('[data-in2publish-confirm]').each(function () { - var element = $(this); - element.on('click', function (event) { - if (element.data('in2publish-confirm')) { - if (element.hasClass('in2publish-stagelisting__item__publish--blocked') || !confirm(element.data('in2publish-confirm'))) { - event.preventDefault(); - event.stopPropagation(); - event.stopImmediatePropagation(); - return; - } - } - if ('TRUE' === element.data('in2publish-overlay')) { - In2publishModule.showPreloader(); - } - }); - }); + document.querySelectorAll('[data-in2publish-confirm]').forEach(element => { + element.addEventListener('click', In2publishModule.overlayHandler, true) + }) }; + /** + * @param {Event} event + */ + In2publishModule.overlayHandler = function (event) { + /** + * @type {HTMLAnchorElement} + */ + const target = event.currentTarget + if ( + target.dataset['in2publishConfirm'] + && ( + target.classList.contains('in2publish-stagelisting__item__publish--blocked') + || !confirm(target.dataset['in2publishConfirm']) + ) + ) { + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); + return; + } + if ('TRUE' === target.dataset['in2publishOverlay']) { + In2publishModule.showPreloader(); + } + } + In2publishModule.showPreloader = function () { In2publishModule.objects.preLoader.removeClass('in2publish-preloader--hidden'); In2publishModule.objects.typo3DocBody.addClass('stopScrolling'); From dbbc018e881a8606914ac9ea929673488b823a8d Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Tue, 15 Mar 2022 14:46:32 +0100 Subject: [PATCH 04/56] [META] Replace extension/module icons Resolves: https://projekte.in2code.de/issues/49147 --- Resources/Public/Icons/Extension.svg | 101 +++------------------------ Resources/Public/Icons/File.svg | 34 ++++----- Resources/Public/Icons/Overview.svg | 21 ++++++ Resources/Public/Icons/Record.svg | 22 ------ Resources/Public/Icons/Redirect.svg | 8 +-- Resources/Public/Icons/Tools.svg | 33 +++------ ext_tables.php | 2 +- 7 files changed, 59 insertions(+), 162 deletions(-) create mode 100644 Resources/Public/Icons/Overview.svg delete mode 100644 Resources/Public/Icons/Record.svg diff --git a/Resources/Public/Icons/Extension.svg b/Resources/Public/Icons/Extension.svg index aa56f27bf..04891ffc3 100644 --- a/Resources/Public/Icons/Extension.svg +++ b/Resources/Public/Icons/Extension.svg @@ -1,95 +1,12 @@ - - - - - - - - - image/svg+xml - - - - - - - - - - - - + + + + + + + + + - - diff --git a/Resources/Public/Icons/File.svg b/Resources/Public/Icons/File.svg index 11be8838f..da2db3865 100644 --- a/Resources/Public/Icons/File.svg +++ b/Resources/Public/Icons/File.svg @@ -1,22 +1,16 @@ - - - in2publish - Created with Sketch. - - - - - - - - - - - - - - - + + + + - \ No newline at end of file + + + + + + + + + + diff --git a/Resources/Public/Icons/Overview.svg b/Resources/Public/Icons/Overview.svg new file mode 100644 index 000000000..5e464dea6 --- /dev/null +++ b/Resources/Public/Icons/Overview.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Resources/Public/Icons/Record.svg b/Resources/Public/Icons/Record.svg deleted file mode 100644 index df9e1caff..000000000 --- a/Resources/Public/Icons/Record.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - in2publish - Created with Sketch. - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Resources/Public/Icons/Redirect.svg b/Resources/Public/Icons/Redirect.svg index 8c29893f4..fe4f43ba8 100644 --- a/Resources/Public/Icons/Redirect.svg +++ b/Resources/Public/Icons/Redirect.svg @@ -82,11 +82,9 @@ inkscape:window-maximized="0" inkscape:current-layer="module-redirects" inkscape:document-rotation="0" /> - + + + - - - in2publish - Created with Sketch. - - - - - - - - - - - - - - - - - + + + + - \ No newline at end of file + + + + + + + diff --git a/ext_tables.php b/ext_tables.php index faca268d9..29231249d 100755 --- a/ext_tables.php +++ b/ext_tables.php @@ -65,7 +65,7 @@ ], [ 'access' => 'user,group', - 'icon' => 'EXT:in2publish_core/Resources/Public/Icons/Record.svg', + 'icon' => 'EXT:in2publish_core/Resources/Public/Icons/Overview.svg', 'labels' => 'LLL:EXT:in2publish_core/Resources/Private/Language/locallang_mod1.xlf', ] ); From 3fb2342e900f00c353429a6043c55b1a1d2552ce Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 13:13:06 +0200 Subject: [PATCH 05/56] [BUGFIX] Prevent undefined index access in DefaultRecordFinder --- .../Component/RecordHandling/DefaultRecordFinder.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Classes/Component/RecordHandling/DefaultRecordFinder.php b/Classes/Component/RecordHandling/DefaultRecordFinder.php index d9af6c274..c2c1dae64 100644 --- a/Classes/Component/RecordHandling/DefaultRecordFinder.php +++ b/Classes/Component/RecordHandling/DefaultRecordFinder.php @@ -455,11 +455,15 @@ protected function convertPropertyArraysToRecords( } } } - if (!$this->isIgnoredRecord((array)$localProperties[$key], (array)$foreignProperties[$key], $tableName)) { + + $localPropertiesArray = (array)($localProperties[$key] ?? []); + $foreignPropertiesArray = (array)($foreignProperties[$key] ?? []); + + if (!$this->isIgnoredRecord($localPropertiesArray, $foreignPropertiesArray, $tableName)) { $foundRecords[$key] = $this->recordFactory->makeInstance( $this, - (array)$localProperties[$key], - (array)$foreignProperties[$key], + $localPropertiesArray, + $foreignPropertiesArray, [], $tableName, 'uid', From 4f7cb8766cc75d01e6a26655469b7abf8b15c415 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 13:16:13 +0200 Subject: [PATCH 06/56] [BUGFIX] Check if a key exists in the TCA instead of relying on unset key behavior --- Classes/Features/SkipEmptyTable/Service/TableInfoService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Features/SkipEmptyTable/Service/TableInfoService.php b/Classes/Features/SkipEmptyTable/Service/TableInfoService.php index 927818680..7ee19aebf 100644 --- a/Classes/Features/SkipEmptyTable/Service/TableInfoService.php +++ b/Classes/Features/SkipEmptyTable/Service/TableInfoService.php @@ -74,8 +74,8 @@ public function isPidInTable(string $table, int $pid): bool protected function queryTableInfo(string $table): array { - $hasPid = $GLOBALS['TCA'][$table]; - if (isset($hasPid)) { + $hasPid = isset($GLOBALS['TCA'][$table]); + if ($hasPid) { $localPids = $this->queryTableFromDatabase($this->localConnection, $table); $foreignPids = $this->queryTableFromDatabase($this->foreignConnection, $table); $uniquePids = array_unique(array_merge($localPids, $foreignPids)); From a51c31fb44b75be25b0583822772fd11d9d93867 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 13:25:09 +0200 Subject: [PATCH 07/56] [BUGFIX] Skip FlexForm select fields without a foreign table --- Classes/Component/RecordHandling/DefaultRecordFinder.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Classes/Component/RecordHandling/DefaultRecordFinder.php b/Classes/Component/RecordHandling/DefaultRecordFinder.php index c2c1dae64..1f325e411 100644 --- a/Classes/Component/RecordHandling/DefaultRecordFinder.php +++ b/Classes/Component/RecordHandling/DefaultRecordFinder.php @@ -1054,6 +1054,9 @@ protected function getRecordsByFlexFormRelation( $recordId = $record->getIdentifier(); switch ($config['type']) { case 'select': + if (empty($config['foreign_table'])) { + break; + } $whereClause = ''; if (!empty($config['foreign_table_where'])) { $whereClause = $config['foreign_table_where']; From 521cbcc737ff473de28439b0f24700666f1124dd Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 13:36:11 +0200 Subject: [PATCH 08/56] [BUGFIX] Respect the actual sortby field from the TCA to detect if records were moved --- Classes/Domain/Factory/RecordFactory.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Classes/Domain/Factory/RecordFactory.php b/Classes/Domain/Factory/RecordFactory.php index 111d273eb..37c95d588 100755 --- a/Classes/Domain/Factory/RecordFactory.php +++ b/Classes/Domain/Factory/RecordFactory.php @@ -419,7 +419,10 @@ protected function detectAndAlterMovedInstance( } elseif (!empty($localProperties['pid']) && !empty($foreignProperties['pid'])) { if ($localProperties['pid'] !== $foreignProperties['pid']) { $hasBeenMoved = true; - } elseif ($localProperties['sorting'] !== $foreignProperties['sorting']) { + } elseif ( + ($sortField = ($GLOBALS['TCA'][$tableName]['ctrl']['sortby'] ?? null)) + && ($localProperties[$sortField] ?? null) !== ($foreignProperties[$sortField] ?? null) + ) { $hasBeenMoved = true; } } From e7d836fbe9bc1a2a8b7aa8eda694b7f9b6dfbb82 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 13:53:54 +0200 Subject: [PATCH 09/56] [BUGFIX] Check if a TCA column MM key is set before accessing it --- Classes/Component/RecordHandling/DefaultRecordFinder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Component/RecordHandling/DefaultRecordFinder.php b/Classes/Component/RecordHandling/DefaultRecordFinder.php index 1f325e411..c80dd22f2 100644 --- a/Classes/Component/RecordHandling/DefaultRecordFinder.php +++ b/Classes/Component/RecordHandling/DefaultRecordFinder.php @@ -1166,7 +1166,7 @@ protected function fetchRelatedRecordsByGroupTypeDb( } } foreach ($identifierToTableMap as $tableName => $identifiers) { - if ($columnConfiguration['MM']) { + if (!empty($columnConfiguration['MM'])) { $this->logger->alert( 'Missing implementation: GROUP MM', [ From 7e92d7bcc1276531dd94ca7ea2c48b547660362d Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Fri, 22 Apr 2022 10:22:21 +0200 Subject: [PATCH 10/56] [BUGFIX] Fix array keys that are used in PHP 8 when using call_user_func_array Resolves: https://projekte.in2code.de/issues/50000 --- Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php b/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php index a2e1345df..21402dc8f 100644 --- a/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php +++ b/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php @@ -670,9 +670,9 @@ public function createFolder($newFolderName, $parentFolderIdentifier = '', $recu EnvelopeDispatcher::CMD_CREATE_FOLDER, [ 'storage' => $this->storageUid, - '$newFolderName' => $newFolderName, - '$parentFolderIdentifier' => $parentFolderIdentifier, - '$recursive' => $recursive, + 'newFolderName' => $newFolderName, + 'parentFolderIdentifier' => $parentFolderIdentifier, + 'recursive' => $recursive, ] ) ); From 039e79d5d628ba99bbda376b044b37b66505a288 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Tue, 19 Apr 2022 17:12:50 +0200 Subject: [PATCH 11/56] [FEATURE] Implement replacement of SITE: markers in TCA Related: https://projekte.in2code.de/issues/49998 --- .../Domain/Service/ReplaceMarkersService.php | 71 ++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/Classes/Domain/Service/ReplaceMarkersService.php b/Classes/Domain/Service/ReplaceMarkersService.php index 41f0b5ee7..23a40b88f 100755 --- a/Classes/Domain/Service/ReplaceMarkersService.php +++ b/Classes/Domain/Service/ReplaceMarkersService.php @@ -36,6 +36,11 @@ use Psr\Log\LoggerAwareTrait; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools; +use TYPO3\CMS\Core\Exception\SiteNotFoundException; +use TYPO3\CMS\Core\Site\Entity\Site; +use TYPO3\CMS\Core\Site\SiteFinder; +use TYPO3\CMS\Core\Utility\ArrayUtility; +use TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException; use TYPO3\CMS\Core\Utility\GeneralUtility; use function explode; @@ -60,10 +65,13 @@ class ReplaceMarkersService implements LoggerAwareInterface protected TcaProcessingService $tcaProcessingService; - public function __construct(FlexFormTools $flexFormTools, TcaProcessingService $tcaProcessingService) + protected SiteFinder $siteFinder; + + public function __construct(FlexFormTools $flexFormTools, TcaProcessingService $tcaProcessingService, SiteFinder $siteFinder) { $this->flexFormTools = $flexFormTools; $this->tcaProcessingService = $tcaProcessingService; + $this->siteFinder = $siteFinder; } /** @@ -85,6 +93,7 @@ public function replaceMarkers(RecordInterface $record, string $string, string $ $string = $this->replacePageMarker($string, $record); $string = $this->replacePageTsConfigMarkers($record, $string, $propertyName); $string = $this->replaceStaticMarker($string); + $string = $this->replaceSiteMarker($string, $record); $this->checkForMarkersAndErrors($string); } return $string; @@ -248,6 +257,66 @@ private function replaceFlexFormFieldMarkers( return $string; } + /** + * Replaces ###SITE:siteConfigKey### markers in TCA with their respective values + * + * @param string $string + * @param RecordInterface $record + * @return array|string|string[] + */ + private function replaceSiteMarker(string $string, RecordInterface $record) + { + if (false !== strpos($string, '###SITE:')) { + /** @var Site|null $site */ + $site = null; + + try { + $site = $this->siteFinder->getSiteByPageId($record->getPageIdentifier()); + } catch (SiteNotFoundException $exception) { + return $string; + } + + preg_match_all('(###SITE:([^#]+)###)', $string, $matches, PREG_SET_ORDER); + + if (empty($matches)) { + return $string; + } + + $configuration = $site->getConfiguration(); + $replacements = []; + + array_walk($matches, function($match) use (&$replacements, &$configuration) { + $setting = $match[1]; + + try { + $value = ArrayUtility::getValueByPath($configuration, $setting, '.'); + } catch (MissingArrayPathException $exception) { + $value = ''; + } + + if (is_string($value)) { + $value = DatabaseUtility::quoteString($value); + } elseif (is_array($value)) { + $value = implode(',', array_map(static function ($item) { + return DatabaseUtility::quoteString($item); + }, $value)); + } elseif (is_bool($value)) { + $value = (int)$value; + } + + $replacements[$match[0]] = $value; + }); + + $string = str_replace( + array_keys($replacements), + array_values($replacements), + $string + ); + } + + return $string; + } + /** * @see \TYPO3\CMS\Backend\Form\FormDataProvider\TcaFlexProcess::getSimplifiedDataStructureIdentifier */ From f5fb1e3165877328f9ae4e26fe60b65fbce644d4 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Tue, 19 Apr 2022 17:13:47 +0200 Subject: [PATCH 12/56] [BUGFIX] Adjust test cases for ReplaceMarkersService to match new constructor Related: https://projekte.in2code.de/issues/49998 --- Tests/Unit/Service/ReplaceMarkersServiceTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tests/Unit/Service/ReplaceMarkersServiceTest.php b/Tests/Unit/Service/ReplaceMarkersServiceTest.php index 005307f13..a9a75c70a 100644 --- a/Tests/Unit/Service/ReplaceMarkersServiceTest.php +++ b/Tests/Unit/Service/ReplaceMarkersServiceTest.php @@ -51,8 +51,9 @@ public function testReplaceMarkerServiceSupportsPageTsConfigId() $flexFormTools = $this->createMock(FlexFormTools::class); $tcaProcessingService = $this->createMock(TcaProcessingService::class); + $siteFinder = $this->createMock(SiteFinder::class); - $replaceMarkerService = new class ($flexFormTools, $tcaProcessingService) extends ReplaceMarkersService { + $replaceMarkerService = new class ($flexFormTools, $tcaProcessingService, $siteFinder) extends ReplaceMarkersService { protected function getPagesTsConfig(int $pageIdentifier): array { return [ @@ -85,8 +86,9 @@ public function testReplaceMarkerServiceSupportsPageTsConfigIdList() $flexFormTools = $this->createMock(FlexFormTools::class); $tcaProcessingService = $this->createMock(TcaProcessingService::class); + $siteFinder = $this->createMock(SiteFinder::class); - $replaceMarkerService = new class ($flexFormTools, $tcaProcessingService) extends ReplaceMarkersService { + $replaceMarkerService = new class ($flexFormTools, $tcaProcessingService, $siteFinder) extends ReplaceMarkersService { protected function getPagesTsConfig(int $pageIdentifier): array { return [ From 89be3a60928de25ce579fdf1b4fee9d2ccf61f08 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Tue, 19 Apr 2022 17:14:38 +0200 Subject: [PATCH 13/56] [TASK] Add test for replaceSiteMarker functionality Related: https://projekte.in2code.de/issues/49998 --- .../Service/ReplaceMarkersServiceTest.php | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Tests/Functional/Service/ReplaceMarkersServiceTest.php diff --git a/Tests/Functional/Service/ReplaceMarkersServiceTest.php b/Tests/Functional/Service/ReplaceMarkersServiceTest.php new file mode 100644 index 000000000..c505530e7 --- /dev/null +++ b/Tests/Functional/Service/ReplaceMarkersServiceTest.php @@ -0,0 +1,79 @@ +getRecordStub('tx_unit_test_table'); + + $flexFormTools = $this->createMock(FlexFormTools::class); + $tcaProcessingService = $this->createMock(TcaProcessingService::class); + + $siteFinder = $this->createMock(SiteFinder::class); + $siteFinder->method('getSiteByPageId')->willReturn( + new Site('test', 1, [ + 'rootPageId' => 1, + 'nested' => [ + 'custom' => 'test' + ], + 'stringArray' => [ + 'string1', + 'string2', + 'string3' + ], + 'boolOption' => false + ]) + ); + + $replaceMarkerService = new ReplaceMarkersService($flexFormTools, $tcaProcessingService, $siteFinder); + + $replacement = $replaceMarkerService->replaceMarkers( + $record, + '###SITE:rootPageId### ###SITE:nested.custom### ###SITE:stringArray### ###SITE:boolOption###', + 'tx_unit_test_field' + ); + + $this->assertSame('1 \'test\' \'string1\',\'string2\',\'string3\' 0', $replacement); + } + + /** + * @param string $table + * @param array $getIgnoreFields + * @param bool $isParentRecordDisabled + * + * @return Record + * + * @SuppressWarnings(PHPMD.BooleanArgumentFlag) + */ + protected function getRecordStub(string $table, array $getIgnoreFields = [], bool $isParentRecordDisabled = false) + { + $config = [ + 'ignoreFieldsForDifferenceView' => [ + $table => $getIgnoreFields, + ], + 'debug' => [ + 'disableParentRecords' => $isParentRecordDisabled, + ], + ]; + $this->initializeIn2publishConfig($config); + + $record = $this->createMock(Record::class); + $record->method('getTablename')->willReturn($table); + return $record; + } +} From fd6ec91029fbc181ed168b50814b4e92607932b1 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Tue, 19 Apr 2022 17:23:29 +0200 Subject: [PATCH 14/56] [TASK] Also replace SITE: markers in FlexForms Related: https://projekte.in2code.de/issues/49998 --- Classes/Domain/Service/ReplaceMarkersService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Classes/Domain/Service/ReplaceMarkersService.php b/Classes/Domain/Service/ReplaceMarkersService.php index 23a40b88f..4b79d1968 100755 --- a/Classes/Domain/Service/ReplaceMarkersService.php +++ b/Classes/Domain/Service/ReplaceMarkersService.php @@ -122,6 +122,7 @@ public function replaceFlexFormMarkers( $string = $this->replacePageMarker($string, $record); $string = $this->replaceFlexFormFieldMarkers($record, $string, $propertyName, $key); $string = $this->replaceStaticMarker($string); + $string = $this->replaceSiteMarker($string, $record); $this->checkForMarkersAndErrors($string); } return $string; From 9e04f8ccee56e901a7e8eae893ed803a8a045738 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Wed, 20 Apr 2022 09:07:52 +0200 Subject: [PATCH 15/56] [BUGFIX] Add missing SiteFinder use statement Related: https://projekte.in2code.de/issues/49998 --- Tests/Unit/Service/ReplaceMarkersServiceTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Unit/Service/ReplaceMarkersServiceTest.php b/Tests/Unit/Service/ReplaceMarkersServiceTest.php index a9a75c70a..ed5493b19 100644 --- a/Tests/Unit/Service/ReplaceMarkersServiceTest.php +++ b/Tests/Unit/Service/ReplaceMarkersServiceTest.php @@ -34,6 +34,7 @@ use In2code\In2publishCore\Domain\Service\TcaProcessingService; use In2code\In2publishCore\Tests\UnitTestCase; use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools; +use TYPO3\CMS\Core\Site\SiteFinder; /** * @coversDefaultClass \In2code\In2publishCore\Domain\Service\ReplaceMarkersService From e75da0a1d9b4e5402c6056fd241dcb3cc0e1902a Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Thu, 21 Apr 2022 11:34:07 +0200 Subject: [PATCH 16/56] [TASK] Apply review feedback Related: https://projekte.in2code.de/issues/49998 --- Classes/Domain/Service/ReplaceMarkersService.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Classes/Domain/Service/ReplaceMarkersService.php b/Classes/Domain/Service/ReplaceMarkersService.php index 4b79d1968..9257cd298 100755 --- a/Classes/Domain/Service/ReplaceMarkersService.php +++ b/Classes/Domain/Service/ReplaceMarkersService.php @@ -61,6 +61,8 @@ class ReplaceMarkersService implements LoggerAwareInterface // Also replace optional quotes around the REC_FIELD_ because we will quote the actual value protected const REC_FIELD_REGEX = '~\'?###REC_FIELD_(.*?)###\'?~'; + protected const SITE_FIELD_REGEX = '(###SITE:([^#]+)###)'; + protected FlexFormTools $flexFormTools; protected TcaProcessingService $tcaProcessingService; @@ -268,16 +270,13 @@ private function replaceFlexFormFieldMarkers( private function replaceSiteMarker(string $string, RecordInterface $record) { if (false !== strpos($string, '###SITE:')) { - /** @var Site|null $site */ - $site = null; - try { $site = $this->siteFinder->getSiteByPageId($record->getPageIdentifier()); } catch (SiteNotFoundException $exception) { return $string; } - preg_match_all('(###SITE:([^#]+)###)', $string, $matches, PREG_SET_ORDER); + preg_match_all(self::SITE_FIELD_REGEX, $string, $matches, PREG_SET_ORDER); if (empty($matches)) { return $string; @@ -286,7 +285,7 @@ private function replaceSiteMarker(string $string, RecordInterface $record) $configuration = $site->getConfiguration(); $replacements = []; - array_walk($matches, function($match) use (&$replacements, &$configuration) { + array_walk($matches, static function($match) use (&$replacements, &$configuration): void { $setting = $match[1]; try { From 0212b845ef5cf50afb4388edc330ea1a374a5197 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Mon, 25 Apr 2022 12:06:46 +0200 Subject: [PATCH 17/56] [REFACTOR] Inject a DB connection in ReplaceMarkersService to get rid of static calls This allows for the test to be a unit test instead of functional. Also, using preg_replace_callback instead of the weird implementation from TYPO3 Resolves: https://projekte.in2code.de/issues/49998 --- .../Domain/Service/ReplaceMarkersService.php | 132 ++++++++++-------- .../Service/ReplaceMarkersServiceTest.php | 79 ----------- .../Service/ReplaceMarkersServiceTest.php | 58 +++++++- 3 files changed, 128 insertions(+), 141 deletions(-) delete mode 100644 Tests/Functional/Service/ReplaceMarkersServiceTest.php rename Tests/Unit/{ => Domain}/Service/ReplaceMarkersServiceTest.php (70%) diff --git a/Classes/Domain/Service/ReplaceMarkersService.php b/Classes/Domain/Service/ReplaceMarkersService.php index 9257cd298..f74b4e083 100755 --- a/Classes/Domain/Service/ReplaceMarkersService.php +++ b/Classes/Domain/Service/ReplaceMarkersService.php @@ -31,26 +31,33 @@ */ use In2code\In2publishCore\Domain\Model\RecordInterface; -use In2code\In2publishCore\Utility\DatabaseUtility; +use InvalidArgumentException; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools; +use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Exception\SiteNotFoundException; -use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Core\Site\SiteFinder; use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException; use TYPO3\CMS\Core\Utility\GeneralUtility; use function explode; +use function gettype; use function implode; +use function is_array; +use function is_bool; use function is_int; +use function is_string; use function json_decode; use function preg_replace_callback; +use function sprintf; use function str_replace; use function strpos; +use const JSON_THROW_ON_ERROR; + /** * Replace markers in TCA definition */ @@ -60,7 +67,6 @@ class ReplaceMarkersService implements LoggerAwareInterface // Also replace optional quotes around the REC_FIELD_ because we will quote the actual value protected const REC_FIELD_REGEX = '~\'?###REC_FIELD_(.*?)###\'?~'; - protected const SITE_FIELD_REGEX = '(###SITE:([^#]+)###)'; protected FlexFormTools $flexFormTools; @@ -69,11 +75,18 @@ class ReplaceMarkersService implements LoggerAwareInterface protected SiteFinder $siteFinder; - public function __construct(FlexFormTools $flexFormTools, TcaProcessingService $tcaProcessingService, SiteFinder $siteFinder) - { + protected Connection $localDatabase; + + public function __construct( + FlexFormTools $flexFormTools, + TcaProcessingService $tcaProcessingService, + SiteFinder $siteFinder, + Connection $localDatabase + ) { $this->flexFormTools = $flexFormTools; $this->tcaProcessingService = $tcaProcessingService; $this->siteFinder = $siteFinder; + $this->localDatabase = $localDatabase; } /** @@ -143,13 +156,13 @@ protected function replaceRecFieldMarker(RecordInterface $record, string $string if (strpos($string, '###REC_FIELD_') !== false) { $string = preg_replace_callback( self::REC_FIELD_REGEX, - static function ($matches) use ($record) { + function ($matches) use ($record) { $propertyName = $matches[1]; $propertyValue = $record->getLocalProperty($propertyName); if ($propertyValue === null) { $propertyValue = $record->getForeignProperty($propertyName); } - return DatabaseUtility::quoteString((string)$propertyValue); + return $this->localDatabase->quote((string)$propertyValue); }, $string ); @@ -177,9 +190,9 @@ protected function replacePageTsConfigMarkers(RecordInterface $record, string $s { if (false !== strpos($string, '###PAGE_TSCONFIG')) { $marker = [ - 'PAGE_TSCONFIG_ID' => fn ($input): int => (int)$input, - 'PAGE_TSCONFIG_IDLIST' => fn ($input): string => implode(',', GeneralUtility::intExplode(',', $input)), - 'PAGE_TSCONFIG_STR' => fn ($input): string => DatabaseUtility::quoteString($input), + 'PAGE_TSCONFIG_ID' => fn($input): int => (int)$input, + 'PAGE_TSCONFIG_IDLIST' => fn($input): string => implode(',', GeneralUtility::intExplode(',', $input)), + 'PAGE_TSCONFIG_STR' => fn($input): string => $this->localDatabase->quote($input), ]; $pageTsConfig = $this->getPagesTsConfig($record->getPageIdentifier()); @@ -221,9 +234,9 @@ private function replaceFlexFormFieldMarkers( $tableName = $record->getTableName(); $marker = [ - 'PAGE_TSCONFIG_ID' => fn ($input): int => (int)$input, - 'PAGE_TSCONFIG_IDLIST' => fn ($input): string => implode(',', GeneralUtility::intExplode(',', $input)), - 'PAGE_TSCONFIG_STR' => fn ($input): string => DatabaseUtility::quoteString($input), + 'PAGE_TSCONFIG_ID' => fn($input): int => (int)$input, + 'PAGE_TSCONFIG_IDLIST' => fn($input): string => implode(',', GeneralUtility::intExplode(',', $input)), + 'PAGE_TSCONFIG_STR' => fn($input): string => $this->localDatabase->quote($input), ]; $pageTs = BackendUtility::getPagesTSconfig($record->getPageIdentifier()); @@ -262,59 +275,64 @@ private function replaceFlexFormFieldMarkers( /** * Replaces ###SITE:siteConfigKey### markers in TCA with their respective values - * - * @param string $string - * @param RecordInterface $record - * @return array|string|string[] */ - private function replaceSiteMarker(string $string, RecordInterface $record) + protected function replaceSiteMarker(string $string, RecordInterface $record): string { - if (false !== strpos($string, '###SITE:')) { - try { - $site = $this->siteFinder->getSiteByPageId($record->getPageIdentifier()); - } catch (SiteNotFoundException $exception) { - return $string; - } + if (false === strpos($string, '###SITE:')) { + return $string; + } - preg_match_all(self::SITE_FIELD_REGEX, $string, $matches, PREG_SET_ORDER); + try { + $site = $this->siteFinder->getSiteByPageId($record->getPageIdentifier()); + } catch (SiteNotFoundException $exception) { + return $string; + } - if (empty($matches)) { - return $string; + $configuration = $site->getConfiguration(); + return preg_replace_callback(self::SITE_FIELD_REGEX, function (array $match) use ($configuration): string { + try { + $value = ArrayUtility::getValueByPath($configuration, $match[1], '.'); + } catch (MissingArrayPathException $exception) { + $value = ''; } + $key = $match[0]; + return (string)$this->quoteParsedSiteConfiguration([$key => $value])[$key]; + }, $string); + } - $configuration = $site->getConfiguration(); - $replacements = []; - - array_walk($matches, static function($match) use (&$replacements, &$configuration): void { - $setting = $match[1]; - - try { - $value = ArrayUtility::getValueByPath($configuration, $setting, '.'); - } catch (MissingArrayPathException $exception) { - $value = ''; - } - - if (is_string($value)) { - $value = DatabaseUtility::quoteString($value); - } elseif (is_array($value)) { - $value = implode(',', array_map(static function ($item) { - return DatabaseUtility::quoteString($item); - }, $value)); - } elseif (is_bool($value)) { - $value = (int)$value; - } - - $replacements[$match[0]] = $value; - }); - - $string = str_replace( - array_keys($replacements), - array_values($replacements), - $string + /** + * @see \TYPO3\CMS\Backend\Form\FormDataProvider\AbstractItemProvider::quoteParsedSiteConfiguration + */ + protected function quoteParsedSiteConfiguration(array $parsedSiteConfiguration): array + { + foreach ($parsedSiteConfiguration as $key => $value) { + if (is_int($value)) { + // int values are safe, nothing to do here + continue; + } + if (is_string($value)) { + $parsedSiteConfiguration[$key] = $this->localDatabase->quote($value); + continue; + } + if (is_array($value)) { + $parsedSiteConfiguration[$key] = implode(',', $this->quoteParsedSiteConfiguration($value)); + continue; + } + if (is_bool($value)) { + $parsedSiteConfiguration[$key] = (int)$value; + continue; + } + throw new InvalidArgumentException( + sprintf( + 'Cannot quote site configuration setting "%s" of type "%s", only "int", "bool", "string" and "array" are supported', + $key, + gettype($value) + ), + 1630324435 ); } - return $string; + return $parsedSiteConfiguration; } /** diff --git a/Tests/Functional/Service/ReplaceMarkersServiceTest.php b/Tests/Functional/Service/ReplaceMarkersServiceTest.php deleted file mode 100644 index c505530e7..000000000 --- a/Tests/Functional/Service/ReplaceMarkersServiceTest.php +++ /dev/null @@ -1,79 +0,0 @@ -getRecordStub('tx_unit_test_table'); - - $flexFormTools = $this->createMock(FlexFormTools::class); - $tcaProcessingService = $this->createMock(TcaProcessingService::class); - - $siteFinder = $this->createMock(SiteFinder::class); - $siteFinder->method('getSiteByPageId')->willReturn( - new Site('test', 1, [ - 'rootPageId' => 1, - 'nested' => [ - 'custom' => 'test' - ], - 'stringArray' => [ - 'string1', - 'string2', - 'string3' - ], - 'boolOption' => false - ]) - ); - - $replaceMarkerService = new ReplaceMarkersService($flexFormTools, $tcaProcessingService, $siteFinder); - - $replacement = $replaceMarkerService->replaceMarkers( - $record, - '###SITE:rootPageId### ###SITE:nested.custom### ###SITE:stringArray### ###SITE:boolOption###', - 'tx_unit_test_field' - ); - - $this->assertSame('1 \'test\' \'string1\',\'string2\',\'string3\' 0', $replacement); - } - - /** - * @param string $table - * @param array $getIgnoreFields - * @param bool $isParentRecordDisabled - * - * @return Record - * - * @SuppressWarnings(PHPMD.BooleanArgumentFlag) - */ - protected function getRecordStub(string $table, array $getIgnoreFields = [], bool $isParentRecordDisabled = false) - { - $config = [ - 'ignoreFieldsForDifferenceView' => [ - $table => $getIgnoreFields, - ], - 'debug' => [ - 'disableParentRecords' => $isParentRecordDisabled, - ], - ]; - $this->initializeIn2publishConfig($config); - - $record = $this->createMock(Record::class); - $record->method('getTablename')->willReturn($table); - return $record; - } -} diff --git a/Tests/Unit/Service/ReplaceMarkersServiceTest.php b/Tests/Unit/Domain/Service/ReplaceMarkersServiceTest.php similarity index 70% rename from Tests/Unit/Service/ReplaceMarkersServiceTest.php rename to Tests/Unit/Domain/Service/ReplaceMarkersServiceTest.php index ed5493b19..b654d420f 100644 --- a/Tests/Unit/Service/ReplaceMarkersServiceTest.php +++ b/Tests/Unit/Domain/Service/ReplaceMarkersServiceTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace In2code\In2publishCore\Tests\Unit\Service; +namespace In2code\In2publishCore\Tests\Unit\Domain\Service; /* * Copyright notice @@ -34,6 +34,8 @@ use In2code\In2publishCore\Domain\Service\TcaProcessingService; use In2code\In2publishCore\Tests\UnitTestCase; use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools; +use TYPO3\CMS\Core\Database\Connection; +use TYPO3\CMS\Core\Site\Entity\Site; use TYPO3\CMS\Core\Site\SiteFinder; /** @@ -46,15 +48,16 @@ class ReplaceMarkersServiceTest extends UnitTestCase * @covers ::replaceMarkers * @covers ::replacePageTsConfigMarkers */ - public function testReplaceMarkerServiceSupportsPageTsConfigId() + public function testReplaceMarkerServiceSupportsPageTsConfigId(): void { $record = $this->getRecordStub('tx_unit_test_table'); $flexFormTools = $this->createMock(FlexFormTools::class); $tcaProcessingService = $this->createMock(TcaProcessingService::class); $siteFinder = $this->createMock(SiteFinder::class); + $connection = $this->createMock(Connection::class); - $replaceMarkerService = new class ($flexFormTools, $tcaProcessingService, $siteFinder) extends ReplaceMarkersService { + $replaceMarkerService = new class ($flexFormTools, $tcaProcessingService, $siteFinder, $connection) extends ReplaceMarkersService { protected function getPagesTsConfig(int $pageIdentifier): array { return [ @@ -81,15 +84,16 @@ protected function getPagesTsConfig(int $pageIdentifier): array * @covers ::replaceMarkers * @covers ::replacePageTsConfigMarkers */ - public function testReplaceMarkerServiceSupportsPageTsConfigIdList() + public function testReplaceMarkerServiceSupportsPageTsConfigIdList(): void { $record = $this->getRecordStub('tx_unit_test_table'); $flexFormTools = $this->createMock(FlexFormTools::class); $tcaProcessingService = $this->createMock(TcaProcessingService::class); $siteFinder = $this->createMock(SiteFinder::class); + $connection = $this->createMock(Connection::class); - $replaceMarkerService = new class ($flexFormTools, $tcaProcessingService, $siteFinder) extends ReplaceMarkersService { + $replaceMarkerService = new class ($flexFormTools, $tcaProcessingService, $siteFinder, $connection) extends ReplaceMarkersService { protected function getPagesTsConfig(int $pageIdentifier): array { return [ @@ -111,6 +115,50 @@ protected function getPagesTsConfig(int $pageIdentifier): array $this->assertSame('foo 52,11,9 bar', $replacement); } + /** + * @covers ::replaceSiteMarker + */ + public function testReplaceSiteMarker(): void + { + $record = $this->getRecordStub('tx_unit_test_table'); + + $flexFormTools = $this->createMock(FlexFormTools::class); + $tcaProcessingService = $this->createMock(TcaProcessingService::class); + $siteFinder = $this->createMock(SiteFinder::class); + $siteFinder->method('getSiteByPageId')->willReturn( + new Site('test', 1, [ + 'rootPageId' => 1, + 'nested' => [ + 'custom' => 'test', + ], + 'stringArray' => [ + 'string1', + 'string2', + 'string3', + ], + 'boolOption' => false, + ]) + ); + $connection = $this->createMock(Connection::class); + $connection->method('quote')->willReturnCallback(static function ($input) { + return "'$input'"; + }); + + $replaceMarkerService = new ReplaceMarkersService( + $flexFormTools, + $tcaProcessingService, + $siteFinder, + $connection + ); + + $replacement = $replaceMarkerService->replaceMarkers( + $record, + '###SITE:rootPageId### ###SITE:nested.custom### ###SITE:stringArray### ###SITE:boolOption###', + 'tx_unit_test_field' + ); + + $this->assertSame('1 \'test\' \'string1\',\'string2\',\'string3\' 0', $replacement); + } /** * @param string $table From 9a943c2e009f6a935426521af48d33e7592fa46a Mon Sep 17 00:00:00 2001 From: Andreas Nedbal Date: Thu, 14 Apr 2022 16:42:11 +0200 Subject: [PATCH 18/56] [BUGFIX] Fix non-existing statement method calls in non-composer mode setups Related: https://projekte.in2code.de/issues/50175 --- .../Command/Foreign/Status/DbConfigTestCommand.php | 2 +- .../Communication/RemoteProcedureCall/Letterbox.php | 4 ++-- .../Domain/Repository/TaskRepository.php | 2 +- .../Component/RecordHandling/DefaultRecordFinder.php | 4 ++-- .../Driver/RemoteFileAbstractionLayerDriver.php | 2 +- Classes/Domain/Factory/FolderRecordFactory.php | 4 ++-- .../Controller/CompareDatabaseToolController.php | 12 ++++++------ .../Service/FileEdgeCacheInvalidationService.php | 4 ++-- .../Domain/Anomaly/SortingPublisher.php | 2 +- .../Controller/RedirectController.php | 2 +- .../Domain/Repository/SysRedirectRepository.php | 10 +++++----- .../Domain/Repository/SingleDatabaseRepository.php | 4 ++-- .../SkipEmptyTable/Service/TableInfoService.php | 4 ++-- .../Domain/Anomaly/SysLogPublisher.php | 2 +- .../Exporter/LogsExporter.php | 2 +- Classes/Service/Database/RawRecordService.php | 2 +- Classes/Service/Database/UidReservationService.php | 4 ++-- .../Testing/Data/FalStorageTestSubjectsProvider.php | 2 +- .../Testing/Tests/Application/AbstractDomainTest.php | 2 +- .../Tests/Database/DatabaseDifferencesTest.php | 2 +- Classes/Utility/BackendUtility.php | 6 +++--- Classes/Utility/DatabaseUtility.php | 6 +++--- .../GetIsoBySysLanguageUidViewHelper.php | 2 +- 23 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Classes/Command/Foreign/Status/DbConfigTestCommand.php b/Classes/Command/Foreign/Status/DbConfigTestCommand.php index 4664aa98a..ee907b544 100644 --- a/Classes/Command/Foreign/Status/DbConfigTestCommand.php +++ b/Classes/Command/Foreign/Status/DbConfigTestCommand.php @@ -60,7 +60,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $queryBuilder->createNamedParameter(ForeignDatabaseConfigTest::DB_CONFIG_TEST_TYPE) ); $queryBuilder->select('*')->from('tx_in2code_in2publish_task')->where($predicates); - $result = $queryBuilder->execute()->fetchAllAssociative(); + $result = $queryBuilder->execute()->fetchAll(); $output->writeln('DB Config: ' . base64_encode(json_encode(array_column($result, 'configuration')))); return Command::SUCCESS; } diff --git a/Classes/Communication/RemoteProcedureCall/Letterbox.php b/Classes/Communication/RemoteProcedureCall/Letterbox.php index 81a261009..f88e0a956 100644 --- a/Classes/Communication/RemoteProcedureCall/Letterbox.php +++ b/Classes/Communication/RemoteProcedureCall/Letterbox.php @@ -129,7 +129,7 @@ public function receiveEnvelope(int $uid, bool $burnEnvelope = true) ->setMaxResults(1); try { $result = $query->execute(); - $envelopeData = $result->fetchAssociative(); + $envelopeData = $result->fetch(); } catch (Throwable $exception) { $this->logger->error( 'Failed to receive envelope [' . $uid . '] "' . $exception . '"', @@ -156,7 +156,7 @@ public function hasUnAnsweredEnvelopes(): bool $query = $database->createQueryBuilder(); $query->getRestrictions()->removeAll(); $query->count('uid')->from(static::TABLE)->where($query->expr()->isNotNull('response')); - return $query->execute()->fetchOne() > 0; + return $query->execute()->fetch() > 0; } return false; } diff --git a/Classes/Component/PostPublishTaskExecution/Domain/Repository/TaskRepository.php b/Classes/Component/PostPublishTaskExecution/Domain/Repository/TaskRepository.php index 83c126065..ebdd9629e 100755 --- a/Classes/Component/PostPublishTaskExecution/Domain/Repository/TaskRepository.php +++ b/Classes/Component/PostPublishTaskExecution/Domain/Repository/TaskRepository.php @@ -139,7 +139,7 @@ public function findByExecutionBegin(DateTime $executionBegin = null): array ->from(self::TASK_TABLE_NAME) ->where($predicates) ->execute() - ->fetchAllAssociative(); + ->fetchAll(); foreach ($tasksPropertiesArray as $taskProperties) { $taskObjects[] = $this->taskFactory->convertToObject($taskProperties); } diff --git a/Classes/Component/RecordHandling/DefaultRecordFinder.php b/Classes/Component/RecordHandling/DefaultRecordFinder.php index c80dd22f2..70478fba2 100644 --- a/Classes/Component/RecordHandling/DefaultRecordFinder.php +++ b/Classes/Component/RecordHandling/DefaultRecordFinder.php @@ -2088,7 +2088,7 @@ protected function findPropertiesByProperty( if (!empty($limit)) { $query->setMaxResults((int)$limit); } - $rows = $query->execute()->fetchAllAssociative(); + $rows = $query->execute()->fetchAll(); return $this->indexRowsByField($indexField, $rows); } @@ -2190,7 +2190,7 @@ public function findPropertiesByProperties( if (!empty($limit)) { $query->setMaxResults((int)$limit); } - $rows = $query->execute()->fetchAllAssociative(); + $rows = $query->execute()->fetchAll(); return $this->indexRowsByField($indexField, $rows); } diff --git a/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php b/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php index 21402dc8f..185166f1f 100644 --- a/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php +++ b/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php @@ -149,7 +149,7 @@ public function initialize(): void ->where($query->expr()->eq('uid', $this->storageUid)) ->setMaxResults(1) ->execute() - ->fetchAssociative(); + ->fetch(); $flexFormService = GeneralUtility::makeInstance(FlexFormService::class); $driverConfiguration = $flexFormService->convertFlexFormContentToArray( $this->remoteDriverSettings['configuration'] diff --git a/Classes/Domain/Factory/FolderRecordFactory.php b/Classes/Domain/Factory/FolderRecordFactory.php index 160c47b66..33a300314 100644 --- a/Classes/Domain/Factory/FolderRecordFactory.php +++ b/Classes/Domain/Factory/FolderRecordFactory.php @@ -753,7 +753,7 @@ protected function countForeignReferences(int $oldUid): int ->andWhere($query->expr()->eq('uid_local', $query->createNamedParameter($oldUid))); try { $result = $query->execute(); - $count = $result->fetchOne(); + $count = $result->fetch(); } catch (Throwable $exception) { $this->logger->critical( 'Could not count foreign references by uid', @@ -773,7 +773,7 @@ protected function countForeignIndices(int $newUid): int ->where($query->expr()->eq('uid', $query->createNamedParameter($newUid))); try { $result = $query->execute(); - $count = $result->fetchOne(); + $count = $result->fetch(); } catch (Throwable $exception) { $this->logger->critical( 'Could not count foreign indices by uid', diff --git a/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php b/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php index f45039414..a4a18c2fd 100644 --- a/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php +++ b/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php @@ -92,9 +92,9 @@ public function compareAction(ComparisonRequest $comparisonRequest = null): void foreach ($tables as $table) { $tableIdentifier = $this->localDatabase->quoteIdentifier($table); - $localResult = $this->localDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchOne(); + $localResult = $this->localDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetch(); $tableIdentifier = $this->foreignDatabase->quoteIdentifier($table); - $foreignResult = $this->foreignDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchOne(); + $foreignResult = $this->foreignDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetch(); if (null === $localResult && null === $foreignResult) { continue; @@ -130,7 +130,7 @@ public function compareAction(ComparisonRequest $comparisonRequest = null): void ) ) ->execute(); - $localRows = array_column($localResult->fetchAllAssociative(), null, 'uid'); + $localRows = array_column($localResult->fetchAll(), null, 'uid'); $foreignQuery = $this->foreignDatabase->createQueryBuilder(); $foreignResult = $foreignQuery->select('*') ->from($table) @@ -141,7 +141,7 @@ public function compareAction(ComparisonRequest $comparisonRequest = null): void ) ) ->execute(); - $foreignRows = array_column($foreignResult->fetchAllAssociative(), null, 'uid'); + $foreignRows = array_column($foreignResult->fetchAll(), null, 'uid'); $uidList = array_unique(array_merge(array_keys($localRows), array_keys($foreignRows))); @@ -201,7 +201,7 @@ public function transferAction(string $table, int $uid, string $expected): void ->where($localQuery->expr()->eq('uid', $localQuery->createNamedParameter($uid))) ->setMaxResults(1); $localResult = $localQuery->execute(); - $localRow = $localResult->fetchAssociative(); + $localRow = $localResult->fetch(); $foreignQuery = $foreignDatabase->createQueryBuilder(); $foreignQuery->getRestrictions()->removeAll(); @@ -210,7 +210,7 @@ public function transferAction(string $table, int $uid, string $expected): void ->where($foreignQuery->expr()->eq('uid', $foreignQuery->createNamedParameter($uid))) ->setMaxResults(1); $foreignResult = $foreignQuery->execute(); - $foreignRow = $foreignResult->fetchAssociative(); + $foreignRow = $foreignResult->fetch(); if (empty($localRow) && empty($foreignRow)) { $this->addFlashMessage( diff --git a/Classes/Features/FileEdgeCacheInvalidator/Domain/Service/FileEdgeCacheInvalidationService.php b/Classes/Features/FileEdgeCacheInvalidator/Domain/Service/FileEdgeCacheInvalidationService.php index 08bdb5c25..94eccb889 100644 --- a/Classes/Features/FileEdgeCacheInvalidator/Domain/Service/FileEdgeCacheInvalidationService.php +++ b/Classes/Features/FileEdgeCacheInvalidator/Domain/Service/FileEdgeCacheInvalidationService.php @@ -112,7 +112,7 @@ protected function selectSysFileReferenceRecords(array $uidList): ResultStatemen protected function addResultsToCollection(ResultStatement $statement, RecordCollection $recordCollection): void { - while ($row = $statement->fetchAssociative()) { + while ($row = $statement->fetch()) { $table = $row['table']; $uid = (int)$row['uid']; $recordCollection->addRecord($table, $uid); @@ -134,7 +134,7 @@ protected function resolveRecordsToPages(RecordCollection $recordCollection): vo $query->where($query->expr()->in('uid', $recordUidList)); $query->groupBy('pid'); $statement = $query->execute(); - while ($page = $statement->fetchOne()) { + while ($page = $statement->fetch()) { $recordCollection->addRecord('pages', $page); } } diff --git a/Classes/Features/PublishSorting/Domain/Anomaly/SortingPublisher.php b/Classes/Features/PublishSorting/Domain/Anomaly/SortingPublisher.php index d39a6c211..aadbe1d30 100644 --- a/Classes/Features/PublishSorting/Domain/Anomaly/SortingPublisher.php +++ b/Classes/Features/PublishSorting/Domain/Anomaly/SortingPublisher.php @@ -87,7 +87,7 @@ public function publishSortingRecursively(): void ->from($tableName) ->where($query->expr()->in('pid', $pidList)); $statement = $query->execute(); - $localRows = $statement->fetchAllAssociative(); + $localRows = $statement->fetchAll(); $updates = []; foreach ($localRows as $localRow) { diff --git a/Classes/Features/RedirectsSupport/Controller/RedirectController.php b/Classes/Features/RedirectsSupport/Controller/RedirectController.php index 56b9734bb..464b66a8d 100644 --- a/Classes/Features/RedirectsSupport/Controller/RedirectController.php +++ b/Classes/Features/RedirectsSupport/Controller/RedirectController.php @@ -113,7 +113,7 @@ public function listAction(Filter $filter = null): void $query = $foreignConnection->createQueryBuilder(); $query->getRestrictions()->removeAll(); $query->select('uid')->from('sys_redirect')->where($query->expr()->eq('deleted', 1)); - $uidList = array_column($query->execute()->fetchAllAssociative(), 'uid'); + $uidList = array_column($query->execute()->fetchAll(), 'uid'); } $this->view->assignMultiple( [ diff --git a/Classes/Features/RedirectsSupport/Domain/Repository/SysRedirectRepository.php b/Classes/Features/RedirectsSupport/Domain/Repository/SysRedirectRepository.php index d1ec16c9f..6d7e21149 100644 --- a/Classes/Features/RedirectsSupport/Domain/Repository/SysRedirectRepository.php +++ b/Classes/Features/RedirectsSupport/Domain/Repository/SysRedirectRepository.php @@ -79,7 +79,7 @@ public function findRawByUris(Connection $connection, array $uris, array $except $query->select('*')->from('sys_redirect')->where(...$predicates); $result = $query->execute(); - return $result->fetchAllAssociative(); + return $result->fetchAll(); } public function findRawByUids(Connection $connection, array $uids): array @@ -94,7 +94,7 @@ public function findRawByUids(Connection $connection, array $uids): array ->from('sys_redirect') ->where($query->expr()->in('uid', $uids)); $result = $query->execute(); - return $result->fetchAllAssociative(); + return $result->fetchAll(); } public function findByRawTarget(Connection $connection, string $target, array $except): array @@ -107,7 +107,7 @@ public function findByRawTarget(Connection $connection, string $target, array $e if (!empty($except)) { $query->andWhere($query->expr()->notIn('uid', $except)); } - return $query->execute()->fetchAllAssociative(); + return $query->execute()->fetchAll(); } /** @return QueryResultInterface */ @@ -137,7 +137,7 @@ public function findHostsOfRedirects(): array ->orderBy('source_host') ->groupBy('source_host') ->execute() - ->fetchAllAssociative(); + ->fetchAll(); } public function findStatusCodesOfRedirects(): array @@ -148,7 +148,7 @@ public function findStatusCodesOfRedirects(): array ->orderBy('target_statuscode') ->groupBy('target_statuscode') ->execute() - ->fetchAllAssociative(); + ->fetchAll(); } protected function getQueryForRedirectsToBePublished(array $uidList): QueryInterface diff --git a/Classes/Features/SimplifiedOverviewAndPublishing/Domain/Repository/SingleDatabaseRepository.php b/Classes/Features/SimplifiedOverviewAndPublishing/Domain/Repository/SingleDatabaseRepository.php index 282c549e2..8e6978ec4 100644 --- a/Classes/Features/SimplifiedOverviewAndPublishing/Domain/Repository/SingleDatabaseRepository.php +++ b/Classes/Features/SimplifiedOverviewAndPublishing/Domain/Repository/SingleDatabaseRepository.php @@ -42,7 +42,7 @@ public function findByProperty(string $table, string $property, array $values): } $result = $query->execute(); - return array_column($result->fetchAllAssociative(), null, 'uid'); + return array_column($result->fetchAll(), null, 'uid'); } public function findMm(string $table, string $property, array $values, string $where): array @@ -56,7 +56,7 @@ public function findMm(string $table, string $property, array $values, string $w $result = $query->execute(); $rows = []; - while ($row = $result->fetchAssociative()) { + while ($row = $result->fetch()) { $rows[$this->buildRecordIndexIdentifier($row)] = $row; } return $rows; diff --git a/Classes/Features/SkipEmptyTable/Service/TableInfoService.php b/Classes/Features/SkipEmptyTable/Service/TableInfoService.php index 7ee19aebf..5612a6d15 100644 --- a/Classes/Features/SkipEmptyTable/Service/TableInfoService.php +++ b/Classes/Features/SkipEmptyTable/Service/TableInfoService.php @@ -96,7 +96,7 @@ protected function isEmpty(Connection $connection, string $table): bool { try { $query = 'SELECT 1 FROM ' . $connection->quoteIdentifier($table) . ';'; - $atLeastOneRowExists = $connection->executeQuery($query)->fetchOne(); + $atLeastOneRowExists = $connection->executeQuery($query)->fetch(); return !$atLeastOneRowExists; } catch (Throwable $exception) { // Ignore any errors. @@ -108,7 +108,7 @@ protected function isEmpty(Connection $connection, string $table): bool protected function queryTableFromDatabase(Connection $connection, string $table): array { $quotedQuery = $connection->quoteIdentifier($table); - $rows = $connection->executeQuery('SELECT DISTINCT `pid` FROM ' . $quotedQuery)->fetchAllAssociative(); + $rows = $connection->executeQuery('SELECT DISTINCT `pid` FROM ' . $quotedQuery)->fetchAll(); return array_column($rows, 'pid'); } } diff --git a/Classes/Features/SysLogPublisher/Domain/Anomaly/SysLogPublisher.php b/Classes/Features/SysLogPublisher/Domain/Anomaly/SysLogPublisher.php index de08b38c8..d96cb76bb 100644 --- a/Classes/Features/SysLogPublisher/Domain/Anomaly/SysLogPublisher.php +++ b/Classes/Features/SysLogPublisher/Domain/Anomaly/SysLogPublisher.php @@ -73,7 +73,7 @@ protected function findLatestSysLogForPage(int $identifier): ?array ->orderBy('uid', 'DESC') ->setMaxResults(1); $result = $query->execute(); - $row = $result->fetchAssociative(); + $row = $result->fetch(); if (!$row) { return null; } diff --git a/Classes/Features/SystemInformationExport/Exporter/LogsExporter.php b/Classes/Features/SystemInformationExport/Exporter/LogsExporter.php index 850f1171d..8d4464e32 100644 --- a/Classes/Features/SystemInformationExport/Exporter/LogsExporter.php +++ b/Classes/Features/SystemInformationExport/Exporter/LogsExporter.php @@ -60,7 +60,7 @@ public function getInformation(): array ->setMaxResults(500) ->orderBy('uid', 'DESC') ->execute() - ->fetchAllAssociative(); + ->fetchAll(); $logsFormatted = []; foreach ($logs as $log) { diff --git a/Classes/Service/Database/RawRecordService.php b/Classes/Service/Database/RawRecordService.php index 72479b565..5fd9adc1c 100644 --- a/Classes/Service/Database/RawRecordService.php +++ b/Classes/Service/Database/RawRecordService.php @@ -76,7 +76,7 @@ protected function fetchRecord(string $table, int $uid, string $side): ?array ->where($query->expr()->eq('uid', $query->createNamedParameter($uid, PDO::PARAM_INT))) ->setMaxResults(1); $statement = $query->execute(); - $result = $statement->fetchAssociative(); + $result = $statement->fetch(); return is_array($result) ? $result : null; } } diff --git a/Classes/Service/Database/UidReservationService.php b/Classes/Service/Database/UidReservationService.php index b8dc3c9a8..c11e25ee8 100644 --- a/Classes/Service/Database/UidReservationService.php +++ b/Classes/Service/Database/UidReservationService.php @@ -110,7 +110,7 @@ protected function isUidFree(int $uid): bool ->from('sys_file') ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid))) ->execute() - ->fetchOne(); + ->fetch(); if (0 !== $numberOfRows) { return false; @@ -128,7 +128,7 @@ protected function fetchSysFileAutoIncrementFromDatabase(Connection $databaseCon ); try { - $tableStatus = $databaseConnection->executeQuery($statement)->fetchAssociative(); + $tableStatus = $databaseConnection->executeQuery($statement)->fetch(); } catch (Throwable $exception) { throw new RuntimeException('Could not select table status from database', 1475242494, $exception); } diff --git a/Classes/Testing/Data/FalStorageTestSubjectsProvider.php b/Classes/Testing/Data/FalStorageTestSubjectsProvider.php index 2dc34e2d1..6c2a04968 100644 --- a/Classes/Testing/Data/FalStorageTestSubjectsProvider.php +++ b/Classes/Testing/Data/FalStorageTestSubjectsProvider.php @@ -107,7 +107,7 @@ protected function fetchStorages(Connection $connection): array ->from('sys_file_storage') ->where($query->expr()->eq('deleted', 0)) ->execute() - ->fetchAllAssociative(); + ->fetchAll(); return array_combine(array_column($rows, 'uid'), $rows); } } diff --git a/Classes/Testing/Tests/Application/AbstractDomainTest.php b/Classes/Testing/Tests/Application/AbstractDomainTest.php index e0a6af612..5a213daf6 100644 --- a/Classes/Testing/Tests/Application/AbstractDomainTest.php +++ b/Classes/Testing/Tests/Application/AbstractDomainTest.php @@ -60,7 +60,7 @@ abstract protected function getConnection(): Connection; public function run(): TestResult { $statement = $this->findAllRootPages(); - $pageIds = array_column($statement->fetchAllAssociative(), 'uid'); + $pageIds = array_column($statement->fetchAll(), 'uid'); if (empty($pageIds)) { return new TestResult(sprintf('application.no_%s_sites_found', $this->prefix), TestResult::WARNING); } diff --git a/Classes/Testing/Tests/Database/DatabaseDifferencesTest.php b/Classes/Testing/Tests/Database/DatabaseDifferencesTest.php index 0d4c77691..a7f8954c9 100644 --- a/Classes/Testing/Tests/Database/DatabaseDifferencesTest.php +++ b/Classes/Testing/Tests/Database/DatabaseDifferencesTest.php @@ -212,7 +212,7 @@ protected function areDifferentDatabases(Connection $local, Connection $foreign) ->where($query->expr()->eq('task_type', $query->createNamedParameter('Backend Test'))) ->execute(); $identical = false; - while ($result = $statement->fetchAssociative()) { + while ($result = $statement->fetch()) { if ($uid === (int)$result['uid'] && $random === (int)$result['configuration']) { $identical = true; break; diff --git a/Classes/Utility/BackendUtility.php b/Classes/Utility/BackendUtility.php index fccaab9e4..5b3c18b80 100755 --- a/Classes/Utility/BackendUtility.php +++ b/Classes/Utility/BackendUtility.php @@ -146,7 +146,7 @@ public static function getPageIdentifier($identifier = null, string $table = nul ->where($query->expr()->eq('uid', (int)key($data[$table]))) ->setMaxResults(1) ->execute() - ->fetchAssociative(); + ->fetch(); if (false !== $result && isset($result['pid'])) { return (int)$result['pid']; } @@ -167,7 +167,7 @@ public static function getPageIdentifier($identifier = null, string $table = nul ->where($query->expr()->eq('uid', (int)$rollbackData[1])) ->setMaxResults(1) ->execute() - ->fetchAssociative(); + ->fetch(); if (false !== $result && isset($result['pid'])) { return (int)$result['pid']; } @@ -184,7 +184,7 @@ public static function getPageIdentifier($identifier = null, string $table = nul ->where($query->expr()->eq('uid', (int)$identifier)) ->setMaxResults(1) ->execute() - ->fetchAssociative(); + ->fetch(); if (isset($row['pid'])) { return (int)$row['pid']; } diff --git a/Classes/Utility/DatabaseUtility.php b/Classes/Utility/DatabaseUtility.php index 9975d71e0..479d1e6c8 100755 --- a/Classes/Utility/DatabaseUtility.php +++ b/Classes/Utility/DatabaseUtility.php @@ -204,7 +204,7 @@ protected static function createBackup(Connection $connection, string $tableName } $res = $connection->executeQuery('SHOW CREATE TABLE ' . $tableName); - $result = $res->fetchAllAssociative(); + $result = $res->fetchAll(); $data .= $result[0]['Create Table'] . ';' . PHP_EOL; @@ -212,7 +212,7 @@ protected static function createBackup(Connection $connection, string $tableName $query->getRestrictions()->removeAll(); $resultSet = $query->select('*')->from($tableName)->execute(); - while (($row = $resultSet->fetchAssociative())) { + while (($row = $resultSet->fetch())) { $data .= 'INSERT INTO ' . $tableName . ' VALUES (' . implode(',', array_map([$connection, 'quote'], $row)) . @@ -310,7 +310,7 @@ public static function copyTableContents(Connection $fromDatabase, Connection $t $query->getRestrictions()->removeAll(); $queryResult = $query->select('*')->from($tableName)->execute(); $rows = $queryResult->rowCount(); - while ($row = $queryResult->fetchAssociative()) { + while ($row = $queryResult->fetch()) { if (1 !== static::insertRow($toDatabase, $tableName, $row)) { throw new In2publishCoreException('Failed to import row into "' . $tableName . '"', 1562570305); } diff --git a/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php b/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php index 16a5c3132..58a490abd 100644 --- a/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php +++ b/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php @@ -66,7 +66,7 @@ public function render(): string ->from(self::TBL_SYS_LANGUAGE) ->where($query->expr()->eq('uid', $query->createNamedParameter($language))); $statement = $query->execute(); - $this->rtc[$language] = (string)$statement->fetchOne(); + $this->rtc[$language] = (string)$statement->fetch(); } return $this->rtc[$language]; From 5d83ed4468fb6db4f83dc1d7683a0734b9776b03 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 26 Apr 2022 11:34:28 +0200 Subject: [PATCH 19/56] [BUGFIX] Replace what used to be fetchOne with fetchColumn Resolves: https://projekte.in2code.de/issues/50175 --- Classes/Communication/RemoteProcedureCall/Letterbox.php | 2 +- Classes/Domain/Factory/FolderRecordFactory.php | 4 ++-- .../Controller/CompareDatabaseToolController.php | 4 ++-- Classes/Service/Database/UidReservationService.php | 2 +- .../Miscellaneous/GetIsoBySysLanguageUidViewHelper.php | 2 +- .../Component/RecordHandling/RecordPublishingTest.php | 4 ++-- Tests/Unit/Utility/BackendUtilityTest.php | 2 +- composer.json | 3 +-- 8 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Classes/Communication/RemoteProcedureCall/Letterbox.php b/Classes/Communication/RemoteProcedureCall/Letterbox.php index f88e0a956..aecb7c5f8 100644 --- a/Classes/Communication/RemoteProcedureCall/Letterbox.php +++ b/Classes/Communication/RemoteProcedureCall/Letterbox.php @@ -156,7 +156,7 @@ public function hasUnAnsweredEnvelopes(): bool $query = $database->createQueryBuilder(); $query->getRestrictions()->removeAll(); $query->count('uid')->from(static::TABLE)->where($query->expr()->isNotNull('response')); - return $query->execute()->fetch() > 0; + return $query->execute()->fetchColumn() > 0; } return false; } diff --git a/Classes/Domain/Factory/FolderRecordFactory.php b/Classes/Domain/Factory/FolderRecordFactory.php index 33a300314..38aec5d81 100644 --- a/Classes/Domain/Factory/FolderRecordFactory.php +++ b/Classes/Domain/Factory/FolderRecordFactory.php @@ -753,7 +753,7 @@ protected function countForeignReferences(int $oldUid): int ->andWhere($query->expr()->eq('uid_local', $query->createNamedParameter($oldUid))); try { $result = $query->execute(); - $count = $result->fetch(); + $count = $result->fetchColumn(); } catch (Throwable $exception) { $this->logger->critical( 'Could not count foreign references by uid', @@ -773,7 +773,7 @@ protected function countForeignIndices(int $newUid): int ->where($query->expr()->eq('uid', $query->createNamedParameter($newUid))); try { $result = $query->execute(); - $count = $result->fetch(); + $count = $result->fetchColumn(); } catch (Throwable $exception) { $this->logger->critical( 'Could not count foreign indices by uid', diff --git a/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php b/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php index a4a18c2fd..0522bd98a 100644 --- a/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php +++ b/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php @@ -92,9 +92,9 @@ public function compareAction(ComparisonRequest $comparisonRequest = null): void foreach ($tables as $table) { $tableIdentifier = $this->localDatabase->quoteIdentifier($table); - $localResult = $this->localDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetch(); + $localResult = $this->localDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchColumn(); $tableIdentifier = $this->foreignDatabase->quoteIdentifier($table); - $foreignResult = $this->foreignDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetch(); + $foreignResult = $this->foreignDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchColumn(); if (null === $localResult && null === $foreignResult) { continue; diff --git a/Classes/Service/Database/UidReservationService.php b/Classes/Service/Database/UidReservationService.php index c11e25ee8..fdfb8601a 100644 --- a/Classes/Service/Database/UidReservationService.php +++ b/Classes/Service/Database/UidReservationService.php @@ -110,7 +110,7 @@ protected function isUidFree(int $uid): bool ->from('sys_file') ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid))) ->execute() - ->fetch(); + ->fetchColumn(); if (0 !== $numberOfRows) { return false; diff --git a/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php b/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php index 58a490abd..c6ef65f45 100644 --- a/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php +++ b/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php @@ -66,7 +66,7 @@ public function render(): string ->from(self::TBL_SYS_LANGUAGE) ->where($query->expr()->eq('uid', $query->createNamedParameter($language))); $statement = $query->execute(); - $this->rtc[$language] = (string)$statement->fetch(); + $this->rtc[$language] = (string)$statement->fetchColumn(); } return $this->rtc[$language]; diff --git a/Tests/Functional/Component/RecordHandling/RecordPublishingTest.php b/Tests/Functional/Component/RecordHandling/RecordPublishingTest.php index 842174d11..4138c7590 100644 --- a/Tests/Functional/Component/RecordHandling/RecordPublishingTest.php +++ b/Tests/Functional/Component/RecordHandling/RecordPublishingTest.php @@ -23,7 +23,7 @@ public function testRelatedRecordsArePublished(): void $query = $foreignConnection->createQueryBuilder(); $query->select('*')->from('sys_language'); $result = $query->execute(); - $rows = $result->fetchAllAssociative(); + $rows = $result->fetchAll(); $this->assertEmpty($rows); $defaultRecordFinder = GeneralUtility::makeInstance(DefaultRecordFinder::class); @@ -35,7 +35,7 @@ public function testRelatedRecordsArePublished(): void $query = $foreignConnection->createQueryBuilder(); $query->select('*')->from('sys_language'); $result = $query->execute(); - $rows = $result->fetchAllAssociative(); + $rows = $result->fetchAll(); $this->assertCount(1, $rows); $this->assertSame(1, $rows[0]['uid']); diff --git a/Tests/Unit/Utility/BackendUtilityTest.php b/Tests/Unit/Utility/BackendUtilityTest.php index 217e20280..72233fd1b 100644 --- a/Tests/Unit/Utility/BackendUtilityTest.php +++ b/Tests/Unit/Utility/BackendUtilityTest.php @@ -60,7 +60,7 @@ protected function setUp(): void $connection->method('getSchemaManager')->willReturn($schemaManager); $result = $this->createMock(MysqliStatement::class); - $result->method('fetchAssociative')->willReturnCallback( + $result->method('fetch')->willReturnCallback( function () { return $this->rows; } diff --git a/composer.json b/composer.json index 0f2acb613..80d3ed4af 100755 --- a/composer.json +++ b/composer.json @@ -14,8 +14,7 @@ "ext-json": "*", "ext-pdo": "*", "ext-zip": "*", - "typo3/cms-core": "^10.4", - "doctrine/dbal": "^2.11.0" + "typo3/cms-core": "^10.4" }, "require-dev": { "typo3/cms-extensionmanager": "^10.4", From b49bab3802a2812572d0054e33e969f88543124f Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Fri, 29 Apr 2022 10:01:54 +0200 Subject: [PATCH 20/56] [BUGFIX] Fallback to the foreign property when identifying files --- Classes/Domain/Factory/FolderRecordFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Domain/Factory/FolderRecordFactory.php b/Classes/Domain/Factory/FolderRecordFactory.php index 38aec5d81..65eda595e 100644 --- a/Classes/Domain/Factory/FolderRecordFactory.php +++ b/Classes/Domain/Factory/FolderRecordFactory.php @@ -806,7 +806,7 @@ protected function moveSameSysFileRecordsToRelatedRecords(array $files): array /** @var RecordInterface[] $fileRecords */ $fileRecords = []; foreach ($files as $idx => $file) { - $localIdentifier = $file->getLocalProperty('identifier'); + $localIdentifier = $file->getLocalProperty('identifier') ?? $file->getForeignProperty('identifier'); if (isset($fileRecords[$localIdentifier])) { $fileRecords[$localIdentifier]->addRelatedRecord($file); unset($files[$idx]); From 5843641e2179d8484ab8f1ebdb26dd98da914017 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Fri, 29 Apr 2022 10:07:25 +0200 Subject: [PATCH 21/56] [BUGFIX] Resolve doctrine/dbal deprecations The support for doctrine/dbal < v2.11 was implented in develop again. For TYPO3 v11, the minimum version of doctrine/dbal is v2.13, so we don't need to support older version Reverts: c3caad6b3e48f1508dcf42b986c79a4ab5281580 --- .../Command/Foreign/Status/DbConfigTestCommand.php | 2 +- .../Communication/RemoteProcedureCall/Letterbox.php | 4 ++-- .../FalHandling/Finder/DefaultFalFinder.php | 4 ++-- .../Domain/Repository/TaskRepository.php | 2 +- .../Component/RecordHandling/DefaultRecordFinder.php | 4 ++-- .../Driver/RemoteFileAbstractionLayerDriver.php | 2 +- .../Controller/CompareDatabaseToolController.php | 12 ++++++------ .../Service/FileEdgeCacheInvalidationService.php | 4 ++-- .../Domain/Anomaly/SortingPublisher.php | 2 +- .../Controller/RedirectController.php | 2 +- .../Domain/Repository/SysRedirectRepository.php | 10 +++++----- .../Domain/Repository/SingleDatabaseRepository.php | 4 ++-- .../SkipEmptyTable/Service/TableInfoService.php | 4 ++-- .../Domain/Anomaly/SysLogPublisher.php | 2 +- .../Exporter/LogsExporter.php | 2 +- Classes/Service/Database/RawRecordService.php | 2 +- Classes/Service/Database/UidReservationService.php | 4 ++-- .../Testing/Data/FalStorageTestSubjectsProvider.php | 2 +- .../Testing/Tests/Application/AbstractDomainTest.php | 2 +- .../Tests/Database/DatabaseDifferencesTest.php | 2 +- Classes/Utility/BackendUtility.php | 6 +++--- Classes/Utility/DatabaseUtility.php | 6 +++--- .../GetIsoBySysLanguageUidViewHelper.php | 2 +- .../RecordHandling/RecordPublishingTest.php | 4 ++-- Tests/Unit/Utility/BackendUtilityTest.php | 2 +- 25 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Classes/Command/Foreign/Status/DbConfigTestCommand.php b/Classes/Command/Foreign/Status/DbConfigTestCommand.php index b64858c15..516b3de6a 100644 --- a/Classes/Command/Foreign/Status/DbConfigTestCommand.php +++ b/Classes/Command/Foreign/Status/DbConfigTestCommand.php @@ -62,7 +62,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $queryBuilder->createNamedParameter(ForeignDatabaseConfigTest::DB_CONFIG_TEST_TYPE) ); $queryBuilder->select('*')->from('tx_in2code_in2publish_task')->where($predicates); - $result = $queryBuilder->execute()->fetchAll(); + $result = $queryBuilder->execute()->fetchAllAssociative(); $value = base64_encode(json_encode(array_column($result, 'configuration'), JSON_THROW_ON_ERROR)); $output->writeln('DB Config: ' . $value); return Command::SUCCESS; diff --git a/Classes/Communication/RemoteProcedureCall/Letterbox.php b/Classes/Communication/RemoteProcedureCall/Letterbox.php index ce8cffde9..3b4ee1acf 100644 --- a/Classes/Communication/RemoteProcedureCall/Letterbox.php +++ b/Classes/Communication/RemoteProcedureCall/Letterbox.php @@ -130,7 +130,7 @@ public function receiveEnvelope(int $uid, bool $burnEnvelope = true) ->setMaxResults(1); try { $result = $query->execute(); - $envelopeData = $result->fetch(); + $envelopeData = $result->fetchAssociative(); } catch (Throwable $exception) { $this->logger->error( 'Failed to receive envelope [' . $uid . '] "' . $exception . '"', @@ -157,7 +157,7 @@ public function hasUnAnsweredEnvelopes(): bool $query = $database->createQueryBuilder(); $query->getRestrictions()->removeAll(); $query->count('uid')->from(static::TABLE)->where($query->expr()->isNotNull('response')); - return $query->execute()->fetchColumn() > 0; + return $query->execute()->fetchOne() > 0; } return false; } diff --git a/Classes/Component/FalHandling/Finder/DefaultFalFinder.php b/Classes/Component/FalHandling/Finder/DefaultFalFinder.php index 93169e7a2..1d0e647df 100644 --- a/Classes/Component/FalHandling/Finder/DefaultFalFinder.php +++ b/Classes/Component/FalHandling/Finder/DefaultFalFinder.php @@ -758,7 +758,7 @@ protected function countForeignReferences(int $oldUid): int ->andWhere($query->expr()->eq('uid_local', $query->createNamedParameter($oldUid))); try { $result = $query->execute(); - $count = $result->fetchColumn(); + $count = $result->fetchOne(); } catch (Throwable $exception) { $this->logger->critical( 'Could not count foreign references by uid', @@ -778,7 +778,7 @@ protected function countForeignIndices(int $newUid): int ->where($query->expr()->eq('uid', $query->createNamedParameter($newUid))); try { $result = $query->execute(); - $count = $result->fetchColumn(); + $count = $result->fetchOne(); } catch (Throwable $exception) { $this->logger->critical( 'Could not count foreign indices by uid', diff --git a/Classes/Component/PostPublishTaskExecution/Domain/Repository/TaskRepository.php b/Classes/Component/PostPublishTaskExecution/Domain/Repository/TaskRepository.php index 7f8fd714f..62c27833e 100755 --- a/Classes/Component/PostPublishTaskExecution/Domain/Repository/TaskRepository.php +++ b/Classes/Component/PostPublishTaskExecution/Domain/Repository/TaskRepository.php @@ -135,7 +135,7 @@ public function findByExecutionBegin(DateTime $executionBegin = null): array ->from(self::TASK_TABLE_NAME) ->where($predicates) ->execute() - ->fetchAll(); + ->fetchAllAssociative(); foreach ($tasksPropertiesArray as $taskProperties) { $taskObjects[] = $this->taskFactory->convertToObject($taskProperties); } diff --git a/Classes/Component/RecordHandling/DefaultRecordFinder.php b/Classes/Component/RecordHandling/DefaultRecordFinder.php index faeae3291..6390166a5 100644 --- a/Classes/Component/RecordHandling/DefaultRecordFinder.php +++ b/Classes/Component/RecordHandling/DefaultRecordFinder.php @@ -2093,7 +2093,7 @@ protected function findPropertiesByProperty( if (!empty($limit)) { $query->setMaxResults((int)$limit); } - $rows = $query->execute()->fetchAll(); + $rows = $query->execute()->fetchAllAssociative(); return $this->indexRowsByField($indexField, $rows); } @@ -2195,7 +2195,7 @@ public function findPropertiesByProperties( if (!empty($limit)) { $query->setMaxResults((int)$limit); } - $rows = $query->execute()->fetchAll(); + $rows = $query->execute()->fetchAllAssociative(); return $this->indexRowsByField($indexField, $rows); } diff --git a/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php b/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php index 164ecbaf9..95f4b7d6f 100644 --- a/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php +++ b/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php @@ -139,7 +139,7 @@ public function initialize(): void ->where($query->expr()->eq('uid', $this->storageUid)) ->setMaxResults(1) ->execute() - ->fetch(); + ->fetchAssociative(); $flexFormService = GeneralUtility::makeInstance(FlexFormService::class); $driverConfiguration = $flexFormService->convertFlexFormContentToArray( $this->remoteDriverSettings['configuration'] diff --git a/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php b/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php index d007b5ddf..fcc7f60f7 100644 --- a/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php +++ b/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php @@ -99,9 +99,9 @@ public function compareAction(ComparisonRequest $comparisonRequest = null): Resp foreach ($tables as $table) { $tableIdentifier = $this->localDatabase->quoteIdentifier($table); - $localResult = $this->localDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchColumn(); + $localResult = $this->localDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchOne(); $tableIdentifier = $this->foreignDatabase->quoteIdentifier($table); - $foreignResult = $this->foreignDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchColumn(); + $foreignResult = $this->foreignDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchOne(); if (null === $localResult && null === $foreignResult) { continue; @@ -137,7 +137,7 @@ public function compareAction(ComparisonRequest $comparisonRequest = null): Resp ) ) ->execute(); - $localRows = array_column($localResult->fetchAll(), null, 'uid'); + $localRows = array_column($localResult->fetchAllAssociative(), null, 'uid'); $foreignQuery = $this->foreignDatabase->createQueryBuilder(); $foreignResult = $foreignQuery->select('*') ->from($table) @@ -148,7 +148,7 @@ public function compareAction(ComparisonRequest $comparisonRequest = null): Resp ) ) ->execute(); - $foreignRows = array_column($foreignResult->fetchAll(), null, 'uid'); + $foreignRows = array_column($foreignResult->fetchAllAssociative(), null, 'uid'); $uidList = array_unique(array_merge(array_keys($localRows), array_keys($foreignRows))); @@ -214,7 +214,7 @@ public function transferAction(string $table, int $uid, string $expected): void ->where($localQuery->expr()->eq('uid', $localQuery->createNamedParameter($uid))) ->setMaxResults(1); $localResult = $localQuery->execute(); - $localRow = $localResult->fetch(); + $localRow = $localResult->fetchAssociative(); $foreignQuery = $foreignDatabase->createQueryBuilder(); $foreignQuery->getRestrictions()->removeAll(); @@ -223,7 +223,7 @@ public function transferAction(string $table, int $uid, string $expected): void ->where($foreignQuery->expr()->eq('uid', $foreignQuery->createNamedParameter($uid))) ->setMaxResults(1); $foreignResult = $foreignQuery->execute(); - $foreignRow = $foreignResult->fetch(); + $foreignRow = $foreignResult->fetchAssociative(); if (empty($localRow) && empty($foreignRow)) { $this->addFlashMessage( diff --git a/Classes/Features/FileEdgeCacheInvalidator/Domain/Service/FileEdgeCacheInvalidationService.php b/Classes/Features/FileEdgeCacheInvalidator/Domain/Service/FileEdgeCacheInvalidationService.php index 88b7aa265..0ffbc6da2 100644 --- a/Classes/Features/FileEdgeCacheInvalidator/Domain/Service/FileEdgeCacheInvalidationService.php +++ b/Classes/Features/FileEdgeCacheInvalidator/Domain/Service/FileEdgeCacheInvalidationService.php @@ -113,7 +113,7 @@ protected function selectSysFileReferenceRecords(array $uidList): Result protected function addResultsToCollection(Result $statement, RecordCollection $recordCollection): void { - while ($row = $statement->fetch()) { + while ($row = $statement->fetchAssociative()) { $table = $row['table']; $uid = (int)$row['uid']; $recordCollection->addRecord($table, $uid); @@ -138,7 +138,7 @@ protected function resolveRecordsToPages(RecordCollection $recordCollection): vo $query->where($query->expr()->in('uid', $recordUidList)); $query->groupBy('pid'); $statement = $query->execute(); - while ($page = $statement->fetch()) { + while ($page = $statement->fetchOne()) { $recordCollection->addRecord('pages', $page); } } diff --git a/Classes/Features/PublishSorting/Domain/Anomaly/SortingPublisher.php b/Classes/Features/PublishSorting/Domain/Anomaly/SortingPublisher.php index 0c3b947fd..eea596c1e 100644 --- a/Classes/Features/PublishSorting/Domain/Anomaly/SortingPublisher.php +++ b/Classes/Features/PublishSorting/Domain/Anomaly/SortingPublisher.php @@ -84,7 +84,7 @@ public function publishSortingRecursively(): void ->from($tableName) ->where($query->expr()->in('pid', $pidList)); $statement = $query->execute(); - $localRows = $statement->fetchAll(); + $localRows = $statement->fetchAllAssociative(); $updates = []; foreach ($localRows as $localRow) { diff --git a/Classes/Features/RedirectsSupport/Controller/RedirectController.php b/Classes/Features/RedirectsSupport/Controller/RedirectController.php index 433bacccb..068ba1dda 100644 --- a/Classes/Features/RedirectsSupport/Controller/RedirectController.php +++ b/Classes/Features/RedirectsSupport/Controller/RedirectController.php @@ -140,7 +140,7 @@ public function listAction(Filter $filter = null, int $page = 1): ResponseInterf $query = $foreignConnection->createQueryBuilder(); $query->getRestrictions()->removeAll(); $query->select('uid')->from('sys_redirect')->where($query->expr()->eq('deleted', 1)); - $uidList = array_column($query->execute()->fetchAll(), 'uid'); + $uidList = array_column($query->execute()->fetchAllAssociative(), 'uid'); } $redirects = $this->sysRedirectRepo->findForPublishing($uidList, $filter); $paginator = new QueryResultPaginator($redirects, $page, 15); diff --git a/Classes/Features/RedirectsSupport/Domain/Repository/SysRedirectRepository.php b/Classes/Features/RedirectsSupport/Domain/Repository/SysRedirectRepository.php index 55fb99d3e..bcc9334b4 100644 --- a/Classes/Features/RedirectsSupport/Domain/Repository/SysRedirectRepository.php +++ b/Classes/Features/RedirectsSupport/Domain/Repository/SysRedirectRepository.php @@ -80,7 +80,7 @@ public function findRawByUris(Connection $connection, array $uris, array $except } $query->select('*')->from('sys_redirect')->where(...$predicates); - return $query->execute()->fetchAll(); + return $query->execute()->fetchAllAssociative(); } public function findRawByUids(Connection $connection, array $uids): array @@ -94,7 +94,7 @@ public function findRawByUids(Connection $connection, array $uids): array $query->select('*') ->from('sys_redirect') ->where($query->expr()->in('uid', $uids)); - return $query->execute()->fetchAll(); + return $query->execute()->fetchAllAssociative(); } public function findByRawTarget(Connection $connection, string $target, array $except): array @@ -107,7 +107,7 @@ public function findByRawTarget(Connection $connection, string $target, array $e if (!empty($except)) { $query->andWhere($query->expr()->notIn('uid', $except)); } - return $query->execute()->fetchAll(); + return $query->execute()->fetchAllAssociative(); } /** @@ -141,7 +141,7 @@ public function findHostsOfRedirects(): array ->orderBy('source_host') ->groupBy('source_host') ->execute() - ->fetchAll(); + ->fetchAllAssociative(); } public function findStatusCodesOfRedirects(): array @@ -152,7 +152,7 @@ public function findStatusCodesOfRedirects(): array ->orderBy('target_statuscode') ->groupBy('target_statuscode') ->execute() - ->fetchAll(); + ->fetchAllAssociative(); } protected function getQueryForRedirectsToBePublished(array $uidList): QueryInterface diff --git a/Classes/Features/SimplifiedOverviewAndPublishing/Domain/Repository/SingleDatabaseRepository.php b/Classes/Features/SimplifiedOverviewAndPublishing/Domain/Repository/SingleDatabaseRepository.php index a78e87857..ce20d91e2 100644 --- a/Classes/Features/SimplifiedOverviewAndPublishing/Domain/Repository/SingleDatabaseRepository.php +++ b/Classes/Features/SimplifiedOverviewAndPublishing/Domain/Repository/SingleDatabaseRepository.php @@ -41,7 +41,7 @@ public function findByProperty(string $table, string $property, array $values): } $result = $query->execute(); - return array_column($result->fetchAll(), null, 'uid'); + return array_column($result->fetchAllAssociative(), null, 'uid'); } public function findMm(string $table, string $property, array $values, string $where): array @@ -55,7 +55,7 @@ public function findMm(string $table, string $property, array $values, string $w $result = $query->execute(); $rows = []; - while ($row = $result->fetch()) { + while ($row = $result->fetchAssociative()) { $rows[$this->buildRecordIndexIdentifier($row)] = $row; } return $rows; diff --git a/Classes/Features/SkipEmptyTable/Service/TableInfoService.php b/Classes/Features/SkipEmptyTable/Service/TableInfoService.php index b183adee2..001c4d8bc 100644 --- a/Classes/Features/SkipEmptyTable/Service/TableInfoService.php +++ b/Classes/Features/SkipEmptyTable/Service/TableInfoService.php @@ -95,7 +95,7 @@ protected function isEmpty(Connection $connection, string $table): bool { try { $query = 'SELECT 1 FROM ' . $connection->quoteIdentifier($table) . ';'; - $atLeastOneRowExists = $connection->executeQuery($query)->fetch(); + $atLeastOneRowExists = $connection->executeQuery($query)->fetchOne(); return !$atLeastOneRowExists; } catch (Throwable $exception) { // Ignore any errors. @@ -107,7 +107,7 @@ protected function isEmpty(Connection $connection, string $table): bool protected function queryTableFromDatabase(Connection $connection, string $table): array { $quotedQuery = $connection->quoteIdentifier($table); - $rows = $connection->executeQuery('SELECT DISTINCT `pid` FROM ' . $quotedQuery)->fetchAll(); + $rows = $connection->executeQuery('SELECT DISTINCT `pid` FROM ' . $quotedQuery)->fetchAllAssociative(); return array_column($rows, 'pid'); } } diff --git a/Classes/Features/SysLogPublisher/Domain/Anomaly/SysLogPublisher.php b/Classes/Features/SysLogPublisher/Domain/Anomaly/SysLogPublisher.php index 432887716..bf70b0355 100644 --- a/Classes/Features/SysLogPublisher/Domain/Anomaly/SysLogPublisher.php +++ b/Classes/Features/SysLogPublisher/Domain/Anomaly/SysLogPublisher.php @@ -71,7 +71,7 @@ protected function findLatestSysLogForPage(int $identifier): ?array ->orderBy('uid', 'DESC') ->setMaxResults(1); $result = $query->execute(); - $row = $result->fetch(); + $row = $result->fetchAssociative(); if (!$row) { return null; } diff --git a/Classes/Features/SystemInformationExport/Exporter/LogsExporter.php b/Classes/Features/SystemInformationExport/Exporter/LogsExporter.php index a7a82036d..72ce71ca0 100644 --- a/Classes/Features/SystemInformationExport/Exporter/LogsExporter.php +++ b/Classes/Features/SystemInformationExport/Exporter/LogsExporter.php @@ -59,7 +59,7 @@ public function getInformation(): array ->setMaxResults(500) ->orderBy('uid', 'DESC') ->execute() - ->fetchAll(); + ->fetchAllAssociative(); $logsFormatted = []; foreach ($logs as $log) { diff --git a/Classes/Service/Database/RawRecordService.php b/Classes/Service/Database/RawRecordService.php index 1bc5c1250..d1fb173b2 100644 --- a/Classes/Service/Database/RawRecordService.php +++ b/Classes/Service/Database/RawRecordService.php @@ -76,7 +76,7 @@ protected function fetchRecord(string $table, int $uid, string $side): ?array ->where($query->expr()->eq('uid', $query->createNamedParameter($uid, PDO::PARAM_INT))) ->setMaxResults(1); $statement = $query->execute(); - $result = $statement->fetch(); + $result = $statement->fetchAssociative(); return is_array($result) ? $result : null; } } diff --git a/Classes/Service/Database/UidReservationService.php b/Classes/Service/Database/UidReservationService.php index fd0baa095..4747c9cce 100644 --- a/Classes/Service/Database/UidReservationService.php +++ b/Classes/Service/Database/UidReservationService.php @@ -107,7 +107,7 @@ protected function isUidFree(int $uid): bool ->from('sys_file') ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid))) ->execute() - ->fetchColumn(); + ->fetchOne(); if (0 !== $numberOfRows) { return false; @@ -125,7 +125,7 @@ protected function fetchSysFileAutoIncrementFromDatabase(Connection $databaseCon ); try { - $tableStatus = $databaseConnection->executeQuery($statement)->fetch(); + $tableStatus = $databaseConnection->executeQuery($statement)->fetchAssociative(); } catch (Throwable $exception) { throw new RuntimeException('Could not select table status from database', 1475242494, $exception); } diff --git a/Classes/Testing/Data/FalStorageTestSubjectsProvider.php b/Classes/Testing/Data/FalStorageTestSubjectsProvider.php index da1730726..f6386d407 100644 --- a/Classes/Testing/Data/FalStorageTestSubjectsProvider.php +++ b/Classes/Testing/Data/FalStorageTestSubjectsProvider.php @@ -103,7 +103,7 @@ protected function fetchStorages(Connection $connection): array ->from('sys_file_storage') ->where($query->expr()->eq('deleted', 0)) ->execute() - ->fetchAll(); + ->fetchAllAssociative(); return array_combine(array_column($rows, 'uid'), $rows); } } diff --git a/Classes/Testing/Tests/Application/AbstractDomainTest.php b/Classes/Testing/Tests/Application/AbstractDomainTest.php index 8b790d411..6534e7c0c 100644 --- a/Classes/Testing/Tests/Application/AbstractDomainTest.php +++ b/Classes/Testing/Tests/Application/AbstractDomainTest.php @@ -59,7 +59,7 @@ abstract protected function getConnection(): Connection; public function run(): TestResult { $statement = $this->findAllRootPages(); - $pageIds = array_column($statement->fetchAll(), 'uid'); + $pageIds = array_column($statement->fetchAllAssociative(), 'uid'); if (empty($pageIds)) { return new TestResult(sprintf('application.no_%s_sites_found', $this->prefix), TestResult::WARNING); } diff --git a/Classes/Testing/Tests/Database/DatabaseDifferencesTest.php b/Classes/Testing/Tests/Database/DatabaseDifferencesTest.php index ff6b5d82b..5ab3248cf 100644 --- a/Classes/Testing/Tests/Database/DatabaseDifferencesTest.php +++ b/Classes/Testing/Tests/Database/DatabaseDifferencesTest.php @@ -218,7 +218,7 @@ protected function areDifferentDatabases(Connection $local, Connection $foreign) ->where($query->expr()->eq('task_type', $query->createNamedParameter('Backend Test'))) ->execute(); $identical = false; - while ($result = $statement->fetch()) { + while ($result = $statement->fetchAssociative()) { if ($uid === (int)$result['uid'] && $random === (int)$result['configuration']) { $identical = true; break; diff --git a/Classes/Utility/BackendUtility.php b/Classes/Utility/BackendUtility.php index a452b04f3..cb6f32c6a 100755 --- a/Classes/Utility/BackendUtility.php +++ b/Classes/Utility/BackendUtility.php @@ -159,7 +159,7 @@ public static function getPageIdentifier($identifier = null, string $table = nul ->where($query->expr()->eq('uid', (int)key($data[$table]))) ->setMaxResults(1) ->execute() - ->fetch(); + ->fetchAssociative(); if (false !== $result && isset($result['pid'])) { return (int)$result['pid']; } @@ -180,7 +180,7 @@ public static function getPageIdentifier($identifier = null, string $table = nul ->where($query->expr()->eq('uid', (int)$rollbackData[1])) ->setMaxResults(1) ->execute() - ->fetch(); + ->fetchAssociative(); if (false !== $result && isset($result['pid'])) { return (int)$result['pid']; } @@ -197,7 +197,7 @@ public static function getPageIdentifier($identifier = null, string $table = nul ->where($query->expr()->eq('uid', (int)$identifier)) ->setMaxResults(1) ->execute() - ->fetch(); + ->fetchAssociative(); if (isset($row['pid'])) { return (int)$row['pid']; } diff --git a/Classes/Utility/DatabaseUtility.php b/Classes/Utility/DatabaseUtility.php index 6f1f76cc1..9cf1948ca 100755 --- a/Classes/Utility/DatabaseUtility.php +++ b/Classes/Utility/DatabaseUtility.php @@ -211,7 +211,7 @@ protected static function createBackup(Connection $connection, string $tableName } $res = $connection->executeQuery('SHOW CREATE TABLE ' . $tableName); - $result = $res->fetchAll(); + $result = $res->fetchAllAssociative(); $data .= $result[0]['Create Table'] . ';' . PHP_EOL; @@ -219,7 +219,7 @@ protected static function createBackup(Connection $connection, string $tableName $query->getRestrictions()->removeAll(); $resultSet = $query->select('*')->from($tableName)->execute(); - while (($row = $resultSet->fetch())) { + while (($row = $resultSet->fetchAssociative())) { $data .= 'INSERT INTO ' . $tableName . ' VALUES (' . implode(',', array_map([$connection, 'quote'], $row)) . @@ -317,7 +317,7 @@ public static function copyTableContents(Connection $fromDatabase, Connection $t $query->getRestrictions()->removeAll(); $queryResult = $query->select('*')->from($tableName)->execute(); $rows = $queryResult->rowCount(); - while ($row = $queryResult->fetch()) { + while ($row = $queryResult->fetchAssociative()) { if (1 !== static::insertRow($toDatabase, $tableName, $row)) { throw new In2publishCoreException('Failed to import row into "' . $tableName . '"', 1562570305); } diff --git a/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php b/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php index c51eba035..d764e7fd4 100644 --- a/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php +++ b/Classes/ViewHelpers/Miscellaneous/GetIsoBySysLanguageUidViewHelper.php @@ -65,7 +65,7 @@ public function render(): string ->from(self::TBL_SYS_LANGUAGE) ->where($query->expr()->eq('uid', $query->createNamedParameter($language))); $statement = $query->execute(); - $this->rtc[$language] = (string)$statement->fetchColumn(); + $this->rtc[$language] = (string)$statement->fetchOne(); } return $this->rtc[$language]; diff --git a/Tests/Functional/Component/RecordHandling/RecordPublishingTest.php b/Tests/Functional/Component/RecordHandling/RecordPublishingTest.php index 63683e068..95d86846a 100644 --- a/Tests/Functional/Component/RecordHandling/RecordPublishingTest.php +++ b/Tests/Functional/Component/RecordHandling/RecordPublishingTest.php @@ -51,7 +51,7 @@ public function testRelatedRecordsArePublished(): void $query = $foreignConnection->createQueryBuilder(); $query->select('*')->from('sys_file_storage'); $result = $query->execute(); - $rows = $result->fetchAll(); + $rows = $result->fetchAllAssociative(); $this->assertEmpty($rows); $defaultRecordFinder = GeneralUtility::makeInstance(DefaultRecordFinder::class); @@ -63,7 +63,7 @@ public function testRelatedRecordsArePublished(): void $query = $foreignConnection->createQueryBuilder(); $query->select('*')->from('sys_file_storage'); $result = $query->execute(); - $rows = $result->fetchAll(); + $rows = $result->fetchAllAssociative(); $this->assertCount(1, $rows); $this->assertSame(2, $rows[0]['uid']); diff --git a/Tests/Unit/Utility/BackendUtilityTest.php b/Tests/Unit/Utility/BackendUtilityTest.php index e28cc8d90..aaa5220ea 100644 --- a/Tests/Unit/Utility/BackendUtilityTest.php +++ b/Tests/Unit/Utility/BackendUtilityTest.php @@ -61,7 +61,7 @@ protected function setUp(): void $connection->method('getSchemaManager')->willReturn($schemaManager); $result = $this->createMock(MysqliStatement::class); - $result->method('fetch')->willReturnCallback( + $result->method('fetchAssociative')->willReturnCallback( function () { return $this->rows; } From 1735cce3d144bdb3d01b85e78290fd40590a6d1e Mon Sep 17 00:00:00 2001 From: Christine Zoglmeier Date: Mon, 20 Dec 2021 14:47:15 +0100 Subject: [PATCH 22/56] [TASK] Do not show publish button if a request is running for publishing of record * Resolves: https://projekte.in2code.de/issues/47941 --- Classes/Domain/Model/Record.php | 6 ++ Classes/Domain/Model/RunningRequest.php | 81 +++++++++++++++++++ .../Repository/RunningRequestRepository.php | 69 ++++++++++++++++ .../Publishing/RunningRequestService.php | 26 ++++++ .../RecursivePublishingEndedListener.php | 70 ++++++++++++++++ .../RecursivePublishingListener.php | 73 +++++++++++++++++ Configuration/Services.yaml | 17 ++++ ext_tables.sql | 12 +++ 8 files changed, 354 insertions(+) create mode 100644 Classes/Domain/Model/RunningRequest.php create mode 100644 Classes/Domain/Repository/RunningRequestRepository.php create mode 100644 Classes/Domain/Service/Publishing/RunningRequestService.php create mode 100644 Classes/EventListener/RecursivePublishingEndedListener.php create mode 100644 Classes/EventListener/RecursivePublishingListener.php diff --git a/Classes/Domain/Model/Record.php b/Classes/Domain/Model/Record.php index 76f1a719f..9495a22f6 100755 --- a/Classes/Domain/Model/Record.php +++ b/Classes/Domain/Model/Record.php @@ -31,6 +31,7 @@ */ use In2code\In2publishCore\Config\ConfigContainer; +use In2code\In2publishCore\Domain\Service\Publishing\RunningRequestService; use In2code\In2publishCore\Domain\Service\TcaProcessingService; use In2code\In2publishCore\Event\VoteIfRecordIsPublishable; use In2code\In2publishCore\Service\Configuration\TcaService; @@ -1152,6 +1153,11 @@ public function isPublishable(): bool if (!$this->isChangedRecursive()) { return false; } + $runningRequestService = GeneralUtility::makeInstance(RunningRequestService::class); + if ($runningRequestService->isPublishingRequestRunningForThisRecord($this)) { + return false; + } + $permissionService = GeneralUtility::makeInstance(PermissionService::class); if (!$permissionService->isUserAllowedToPublish()) { return false; diff --git a/Classes/Domain/Model/RunningRequest.php b/Classes/Domain/Model/RunningRequest.php new file mode 100644 index 000000000..21db81097 --- /dev/null +++ b/Classes/Domain/Model/RunningRequest.php @@ -0,0 +1,81 @@ +recordId = $recordId; + $this->tableName = $tableName; + $this->requestToken = $requestToken; + $this->timestampBegin = ($timestampBegin > 0 ? $timestampBegin : time()); + } + + public function getRecordId(): int + { + return $this->recordId; + } + + public function setRecordId(int $recordId) + { + $this->recordId = $recordId; + + } + + public function getTableName(): string + { + return $this->tableName; + } + + public function setTableName(string $tableName) + { + $this->tableName = $tableName; + + } + + public function getRequestToken(): string + { + return $this->requestToken; + } + + public function setRequestToken(string $requestToken) + { + $this->requestToken = $requestToken; + + } + + public function getTimestampBegin(): int + { + return $this->timestampBegin; + } + + public function setTimestampBegin(int $timestampBegin) + { + $this->timestampBegin = $timestampBegin; + } + +} diff --git a/Classes/Domain/Repository/RunningRequestRepository.php b/Classes/Domain/Repository/RunningRequestRepository.php new file mode 100644 index 000000000..8c7033da0 --- /dev/null +++ b/Classes/Domain/Repository/RunningRequestRepository.php @@ -0,0 +1,69 @@ +connection = DatabaseUtility::buildLocalDatabaseConnection(); + } + + public function add(RunningRequest $runningRequest): void + { + $this->connection->insert( + self::RUNNING_REQUEST_TABLE_NAME, + $this->mapProperties($runningRequest) + ); + } + + /** + * @throws \Doctrine\DBAL\Exception + */ + public function containsRunningRequestForRecord(Record $record): bool + { + $statement = $this->connection->select( + ['uid'], + self::RUNNING_REQUEST_TABLE_NAME, + [ + 'record_id' => $record->getIdentifier(), + 'table_name' => $record->getTableName() + ] + ); + return $statement->rowCount() > 0; + } + + public function deleteAllByRecordTableAndRecordIdentifier(string $table, int $identifier): void + { + $query = $this->connection->createQueryBuilder(); + $query->delete(self::RUNNING_REQUEST_TABLE_NAME) + ->where($query->expr()->eq('table_name', $query->createNamedParameter($table))) + ->andWhere($query->expr()->eq('record_id', $query->createNamedParameter($identifier))) + ->execute(); + } + + protected function mapProperties(RunningRequest $runningRequest): array + { + return [ + 'record_id' => $runningRequest->getRecordId(), + 'table_name' => $runningRequest->getTableName(), + 'request_token' => $runningRequest->getRequestToken(), + 'timestamp_begin' => $runningRequest->getTimestampBegin() + ]; + } +} diff --git a/Classes/Domain/Service/Publishing/RunningRequestService.php b/Classes/Domain/Service/Publishing/RunningRequestService.php new file mode 100644 index 000000000..4a38dfc85 --- /dev/null +++ b/Classes/Domain/Service/Publishing/RunningRequestService.php @@ -0,0 +1,26 @@ +runningRequestRepository = $runningRequestRepository; + } + + public function isPublishingRequestRunningForThisRecord(Record $record): bool + { + return $this->runningRequestRepository->containsRunningRequestForRecord($record); + } +} diff --git a/Classes/EventListener/RecursivePublishingEndedListener.php b/Classes/EventListener/RecursivePublishingEndedListener.php new file mode 100644 index 000000000..a4b19bb60 --- /dev/null +++ b/Classes/EventListener/RecursivePublishingEndedListener.php @@ -0,0 +1,70 @@ + + * Christine Zoglmeier + * + * 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! + */ + +use In2code\In2publishCore\Domain\Model\Record; +use In2code\In2publishCore\Domain\Repository\RunningRequestRepository; +use In2code\In2publishCore\Event\RecursiveRecordPublishingEnded; + +class RecursivePublishingEndedListener +{ + /** @var RunningRequestRepository */ + protected $runningRequestRepository; + + public function __construct(RunningRequestRepository $runningRequestRepository) + { + $this->runningRequestRepository = $runningRequestRepository; + } + public function onRecordPublishingEnded(RecursiveRecordPublishingEnded $event): void + { + /** @var Record $record */ + $record = $event->getRecord(); + + $this->deleteFromRunningRequestsTable($record); + foreach ($record->getRelatedRecords() as $tableName => $relatedRecords) { + foreach ($relatedRecords as $relatedRecord) { + $this->deleteFromRunningRequestsTable($relatedRecord); + } + } + } + + /** + * @param Record $record + * @return mixed + */ + protected function deleteFromRunningRequestsTable(Record $record) + { + $recordId = $record->getIdentifier(); + $tableName = $record->getTableName(); + + $this->runningRequestRepository->deleteAllByRecordTableAndRecordIdentifier($tableName, $recordId); + } +} diff --git a/Classes/EventListener/RecursivePublishingListener.php b/Classes/EventListener/RecursivePublishingListener.php new file mode 100644 index 000000000..38df54c26 --- /dev/null +++ b/Classes/EventListener/RecursivePublishingListener.php @@ -0,0 +1,73 @@ + + * Christine Zoglmeier + * + * 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! + */ + +use In2code\In2publishCore\Domain\Model\Record; +use In2code\In2publishCore\Domain\Model\RunningRequest; +use In2code\In2publishCore\Domain\Repository\RunningRequestRepository; +use In2code\In2publishCore\Event\RecursiveRecordPublishingBegan; + +class RecursivePublishingListener +{ + /** @var RunningRequestRepository */ + protected $runningRequestRepository; + + public function __construct(RunningRequestRepository $runningRequestRepository) + { + $this->runningRequestRepository = $runningRequestRepository; + } + public function onRecordPublishingBegan(RecursiveRecordPublishingBegan $event): void + { + /** @var Record $record */ + $record = $event->getRecord(); + + $this->writeToRunningRequestsTable($record); + foreach ($record->getRelatedRecords() as $tableName => $relatedRecords) { + foreach ($relatedRecords as $relatedRecord) { + $this->writeToRunningRequestsTable($relatedRecord); + } + } + } + + /** + * @param Record $record + * @return mixed + */ + protected function writeToRunningRequestsTable(Record $record) + { + $recordId = $record->getIdentifier(); + $tableName = $record->getTableName(); + $requestToken = $_REQUEST['token']; + + $runningRequest = new RunningRequest($recordId, $tableName, $requestToken); + $this->runningRequestRepository->add($runningRequest); + } +} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index ac7e2b5da..9288b1697 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -68,6 +68,9 @@ services: In2code\In2publishCore\Service\Permission\PermissionService: public: true + In2code\In2publishCore\Domain\Service\Publishing\RunningRequestService: + public: true + In2code\In2publishCore\Domain\Repository\TaskRepository: public: true @@ -99,3 +102,17 @@ services: identifier: 'in2publishcore-postprocessingeventlistener-rootrecordcreationwasfinished' method: 'onRootRecordCreationWasFinished' event: In2code\In2publishCore\Event\RootRecordCreationWasFinished + + In2code\In2publishCore\EventListener\RecursivePublishingListener: + tags: + - name: event.listener + identifier: 'in2publishcore-recursivePublishingListener-recursiverecordpublishingbegan' + method: 'onRecordPublishingBegan' + event: In2code\In2publishCore\Event\RecursiveRecordPublishingBegan + + In2code\In2publishCore\EventListener\RecursivePublishingEndedListener: + tags: + - name: event.listener + identifier: 'in2publishcore-recursivePublishingEndedListener-recursiverecordpublishingended' + method: 'onRecordPublishingEnded' + event: In2code\In2publishCore\Event\RecursiveRecordPublishingEnded diff --git a/ext_tables.sql b/ext_tables.sql index 5e48a46a4..e1c74a2cd 100755 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -29,6 +29,18 @@ CREATE TABLE tx_in2code_in2publish_task PRIMARY KEY (uid) ) ENGINE = InnoDB; +CREATE TABLE tx_in2publishcore_running_request +( + uid int(11) unsigned NOT NULL auto_increment, + + record_id int(11) unsigned NOT NULL, + table_name varchar(255) DEFAULT '' NOT NULL, + request_token varchar(255) DEFAULT '' NOT NULL, + timestamp_begin int(11) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid) +) ENGINE = InnoDB; + CREATE TABLE tx_in2code_in2publish_envelope ( uid int(11) unsigned NOT NULL auto_increment, From 75e9b3e92ecc0fd1eab6b21cb205c7b69aa764ed Mon Sep 17 00:00:00 2001 From: Christine Zoglmeier Date: Tue, 21 Dec 2021 08:48:04 +0100 Subject: [PATCH 23/56] [REFACTOR] Move denial of publishing of running request from record to PublishingRequestIsRunningVoter --- Classes/Domain/Model/Record.php | 5 --- .../Repository/RunningRequestRepository.php | 6 ++-- .../Publishing/RunningRequestService.php | 8 +++-- .../PublishingRequestIsRunningVoter.php | 33 +++++++++++++++++++ Configuration/Services.yaml | 7 ++++ 5 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 Classes/EventListener/PublishingRequestIsRunningVoter.php diff --git a/Classes/Domain/Model/Record.php b/Classes/Domain/Model/Record.php index 9495a22f6..5c41f56df 100755 --- a/Classes/Domain/Model/Record.php +++ b/Classes/Domain/Model/Record.php @@ -31,7 +31,6 @@ */ use In2code\In2publishCore\Config\ConfigContainer; -use In2code\In2publishCore\Domain\Service\Publishing\RunningRequestService; use In2code\In2publishCore\Domain\Service\TcaProcessingService; use In2code\In2publishCore\Event\VoteIfRecordIsPublishable; use In2code\In2publishCore\Service\Configuration\TcaService; @@ -1153,10 +1152,6 @@ public function isPublishable(): bool if (!$this->isChangedRecursive()) { return false; } - $runningRequestService = GeneralUtility::makeInstance(RunningRequestService::class); - if ($runningRequestService->isPublishingRequestRunningForThisRecord($this)) { - return false; - } $permissionService = GeneralUtility::makeInstance(PermissionService::class); if (!$permissionService->isUserAllowedToPublish()) { diff --git a/Classes/Domain/Repository/RunningRequestRepository.php b/Classes/Domain/Repository/RunningRequestRepository.php index 8c7033da0..2fa7d18c8 100644 --- a/Classes/Domain/Repository/RunningRequestRepository.php +++ b/Classes/Domain/Repository/RunningRequestRepository.php @@ -35,14 +35,14 @@ public function add(RunningRequest $runningRequest): void /** * @throws \Doctrine\DBAL\Exception */ - public function containsRunningRequestForRecord(Record $record): bool + public function existsRunningRequestForRecord(int $identifier, string $tableName): bool { $statement = $this->connection->select( ['uid'], self::RUNNING_REQUEST_TABLE_NAME, [ - 'record_id' => $record->getIdentifier(), - 'table_name' => $record->getTableName() + 'record_id' => $identifier, + 'table_name' => $tableName ] ); return $statement->rowCount() > 0; diff --git a/Classes/Domain/Service/Publishing/RunningRequestService.php b/Classes/Domain/Service/Publishing/RunningRequestService.php index 4a38dfc85..9b6cca95a 100644 --- a/Classes/Domain/Service/Publishing/RunningRequestService.php +++ b/Classes/Domain/Service/Publishing/RunningRequestService.php @@ -4,7 +4,6 @@ namespace In2code\In2publishCore\Domain\Service\Publishing; -use In2code\In2publishCore\Domain\Model\Record; use In2code\In2publishCore\Domain\Repository\RunningRequestRepository; class RunningRequestService @@ -19,8 +18,11 @@ public function __construct(RunningRequestRepository $runningRequestRepository ) $this->runningRequestRepository = $runningRequestRepository; } - public function isPublishingRequestRunningForThisRecord(Record $record): bool + /** + * @throws \Doctrine\DBAL\Exception + */ + public function isPublishingRequestRunningForThisRecord(int $identifier, string $tableName): bool { - return $this->runningRequestRepository->containsRunningRequestForRecord($record); + return $this->runningRequestRepository->existsRunningRequestForRecord($identifier, $tableName); } } diff --git a/Classes/EventListener/PublishingRequestIsRunningVoter.php b/Classes/EventListener/PublishingRequestIsRunningVoter.php new file mode 100644 index 000000000..239ca9b82 --- /dev/null +++ b/Classes/EventListener/PublishingRequestIsRunningVoter.php @@ -0,0 +1,33 @@ +runningRequestService = $runningRequestService; + } + + /** + * @throws \Doctrine\DBAL\Exception + */ + public function isPublishable(VoteIfRecordIsPublishable $event): void + { + $tableName = $event->getTable(); + $identifier = $event->getIdentifier(); + if ($this->runningRequestService->isPublishingRequestRunningForThisRecord($identifier, $tableName)) { + $event->voteNo(); + } else { + $event->voteYes(); + } + } +} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 9288b1697..b0b8038a1 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -116,3 +116,10 @@ services: identifier: 'in2publishcore-recursivePublishingEndedListener-recursiverecordpublishingended' method: 'onRecordPublishingEnded' event: In2code\In2publishCore\Event\RecursiveRecordPublishingEnded + + In2code\In2publishCore\EventListener\PublishingRequestIsRunningVoter: + tags: + - name: event.listener + identifier: 'in2publishcore-publishingRequestIsRunningVoter-VoteIfRecordIsPublishable' + method: 'isPublishable' + event: In2code\In2publishCore\Event\VoteIfRecordIsPublishable From b019486cdc7e2a57ef86be1e3e3768d80711cb46 Mon Sep 17 00:00:00 2001 From: Christine Zoglmeier Date: Tue, 21 Dec 2021 12:31:03 +0100 Subject: [PATCH 24/56] [TASK] Add a publish tools test checking the existence of a garbage collector task for table tx_in2publishcore_running_request --- .../Database/TableGarbageCollectorTest.php | 53 +++++++++++++++++++ .../Private/Language/de.locallang.testing.xlf | 11 ++++ .../Private/Language/locallang.testing.xlf | 9 ++++ ext_localconf.php | 9 +++- ext_tables.php | 1 + 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 Classes/Testing/Tests/Database/TableGarbageCollectorTest.php diff --git a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php new file mode 100644 index 000000000..57fbab9ba --- /dev/null +++ b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php @@ -0,0 +1,53 @@ +isConnected()) { + return new TestResult('database.local_offline', TestResult::ERROR); + } + + $query = $localDatabase->createQueryBuilder(); + $statement = $query->select('*') + ->from('tx_scheduler_task') + ->where($query->expr()->like( + 'serialized_task_object', + $query->createNamedParameter('%tx_in2publishcore_running_request%')) + ) + ->execute(); + $garbageCollectionTasksExists = $statement->rowCount() > 0; + + + + if ($garbageCollectionTasksExists == false) { + return new TestResult( + 'database.garbage_collector_task_missing', + TestResult::ERROR + ); + } + + return new TestResult('database.garbage_collector_task_exists'); + } + + public function getDependencies(): array + { + return []; + } + +} diff --git a/Resources/Private/Language/de.locallang.testing.xlf b/Resources/Private/Language/de.locallang.testing.xlf index ec3968f37..d6d171cfe 100644 --- a/Resources/Private/Language/de.locallang.testing.xlf +++ b/Resources/Private/Language/de.locallang.testing.xlf @@ -174,6 +174,17 @@ Die Funktion "ssh2_sftp_chmod" steht ab der Version 0.12 von php_ssh2 zu Verfügung. Upgraden Sie php_ssh2 oder ignorieren Sie diese Meldung. + + + A table garbage collector task for table tx_in2publishcore_running_request is missing + Es muss ein Table Garbage Collector Task für die Tabelle tx_in2publishcore_running_request angelegt werden + + + + A table garbage collector task for table tx_in2publishcore_running_request exists + Ein Table Garbage Collector Task für die Tabelle tx_in2publishcore_running_request ist vorhanden + + diff --git a/Resources/Private/Language/locallang.testing.xlf b/Resources/Private/Language/locallang.testing.xlf index 233988e99..a9342f9c3 100644 --- a/Resources/Private/Language/locallang.testing.xlf +++ b/Resources/Private/Language/locallang.testing.xlf @@ -124,6 +124,15 @@ These tables differ: + + + A table garbage collector task for table tx_in2publishcore_running_request is missing + + + + A table garbage collector task for table tx_in2publishcore_running_request exists + + diff --git a/ext_localconf.php b/ext_localconf.php index c6d978e53..63bf615dc 100755 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -100,7 +100,14 @@ [\In2code\In2publishCore\Controller\FrontendController::class => 'preview'], [\In2code\In2publishCore\Controller\FrontendController::class => 'preview'] ); - + /******************************************** Configure Garbage Collector ****************************************/ + // Register table tx_in2publishcore_running_request in table garbage collector + if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\TableGarbageCollectionTask::class]['options']['tables']['tx_in2publishcore_running_request'])) { + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\TableGarbageCollectionTask::class]['options']['tables']['tx_in2publishcore_running_request'] = [ + 'dateField' => 'timestamp_begin', + 'expirePeriod' => 1, + ]; + } /***************************************** Register Communication Adapter *****************************************/ $adapterRegistry->registerAdapter( \In2code\In2publishCore\Communication\RemoteCommandExecution\RemoteAdapter\SshAdapter::ADAPTER_TYPE, diff --git a/ext_tables.php b/ext_tables.php index 29231249d..c0d704a54 100755 --- a/ext_tables.php +++ b/ext_tables.php @@ -127,6 +127,7 @@ $GLOBALS['in2publish_core']['tests'][] = \In2code\In2publishCore\Testing\Tests\Performance\ForeignDbInitializationPerformanceTest::class; $GLOBALS['in2publish_core']['tests'][] = \In2code\In2publishCore\Testing\Tests\Performance\DiskSpeedPerformanceTest::class; $GLOBALS['in2publish_core']['tests'][] = \In2code\In2publishCore\Testing\Tests\Application\SiteConfigurationTest::class; + $GLOBALS['in2publish_core']['tests'][] = \In2code\In2publishCore\Testing\Tests\Database\TableGarbageCollectorTest::class; /************************************************ Redirect Support ************************************************/ if ( From 68bc136e77cadff2be14a618b32cd9015386a07b Mon Sep 17 00:00:00 2001 From: Christine Zoglmeier Date: Thu, 13 Jan 2022 08:58:02 +0100 Subject: [PATCH 25/56] [BUGFIX] Fix label for missing garbage collector task --- Resources/Private/Language/locallang.testing.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Private/Language/locallang.testing.xlf b/Resources/Private/Language/locallang.testing.xlf index a9342f9c3..6335b69b7 100644 --- a/Resources/Private/Language/locallang.testing.xlf +++ b/Resources/Private/Language/locallang.testing.xlf @@ -125,7 +125,7 @@ - + A table garbage collector task for table tx_in2publishcore_running_request is missing From 8ae4d589bd187f1141a68f28c43d388757cc515f Mon Sep 17 00:00:00 2001 From: Christine Zoglmeier Date: Thu, 13 Jan 2022 09:08:46 +0100 Subject: [PATCH 26/56] [CODESTYLE] Remove blank lines --- Classes/Testing/Tests/Database/TableGarbageCollectorTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php index 57fbab9ba..e635da0fb 100644 --- a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php +++ b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php @@ -33,8 +33,6 @@ public function run(): TestResult ->execute(); $garbageCollectionTasksExists = $statement->rowCount() > 0; - - if ($garbageCollectionTasksExists == false) { return new TestResult( 'database.garbage_collector_task_missing', @@ -49,5 +47,4 @@ public function getDependencies(): array { return []; } - } From 294318626bd228db01d889388db9accb5adf4323 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 13 Apr 2022 12:06:57 +0200 Subject: [PATCH 27/56] [FEATURE] Add Record::isPublishing to determine if a record is currently being published Resolves: https://projekte.in2code.de/issues/49152 --- Classes/Domain/Model/Record.php | 9 +++ Classes/Domain/Model/RecordInterface.php | 2 + .../Repository/RunningRequestRepository.php | 39 +++++----- .../Publishing/RunningRequestService.php | 59 ++++++++++++--- .../Event/DetermineIfRecordIsPublishing.php | 52 +++++++++++++ .../PublishingRequestIsRunningVoter.php | 33 --------- .../RecursivePublishingEndedListener.php | 70 ------------------ .../RecursivePublishingListener.php | 73 ------------------- Configuration/Services.yaml | 22 +++--- 9 files changed, 138 insertions(+), 221 deletions(-) create mode 100644 Classes/Event/DetermineIfRecordIsPublishing.php delete mode 100644 Classes/EventListener/PublishingRequestIsRunningVoter.php delete mode 100644 Classes/EventListener/RecursivePublishingEndedListener.php delete mode 100644 Classes/EventListener/RecursivePublishingListener.php diff --git a/Classes/Domain/Model/Record.php b/Classes/Domain/Model/Record.php index 5c41f56df..96bd0c919 100755 --- a/Classes/Domain/Model/Record.php +++ b/Classes/Domain/Model/Record.php @@ -32,6 +32,7 @@ use In2code\In2publishCore\Config\ConfigContainer; use In2code\In2publishCore\Domain\Service\TcaProcessingService; +use In2code\In2publishCore\Event\DetermineIfRecordIsPublishing; use In2code\In2publishCore\Event\VoteIfRecordIsPublishable; use In2code\In2publishCore\Service\Configuration\TcaService; use In2code\In2publishCore\Service\Permission\PermissionService; @@ -1163,6 +1164,14 @@ public function isPublishable(): bool return $event->getVotingResult(); } + public function isPublishing(): bool + { + $eventDispatcher = GeneralUtility::makeInstance(EventDispatcher::class); + $event = new DetermineIfRecordIsPublishing($this->tableName, $this->getIdentifier()); + $eventDispatcher->dispatch($event); + return $event->isPublishing(); + } + public function isRemovedFromLocalDatabase(): bool { return $this->isForeignRecordDeleted() && !$this->isRecordRepresentByProperties($this->localProperties); diff --git a/Classes/Domain/Model/RecordInterface.php b/Classes/Domain/Model/RecordInterface.php index 0c26ea721..0a99f4018 100755 --- a/Classes/Domain/Model/RecordInterface.php +++ b/Classes/Domain/Model/RecordInterface.php @@ -260,5 +260,7 @@ public function getRecordLanguage(): int; public function isPublishable(): bool; + public function isPublishing(): bool; + public function isRemovedFromLocalDatabase(): bool; } diff --git a/Classes/Domain/Repository/RunningRequestRepository.php b/Classes/Domain/Repository/RunningRequestRepository.php index 2fa7d18c8..0fec5e243 100644 --- a/Classes/Domain/Repository/RunningRequestRepository.php +++ b/Classes/Domain/Repository/RunningRequestRepository.php @@ -1,10 +1,9 @@ connection->select( - ['uid'], - self::RUNNING_REQUEST_TABLE_NAME, - [ - 'record_id' => $identifier, - 'table_name' => $tableName - ] - ); - return $statement->rowCount() > 0; + if (!isset($this->rtc['content'])) { + $rows = $this->connection->select(['*'], self::RUNNING_REQUEST_TABLE_NAME); + foreach ($rows as $row) { + $this->rtc['content'][$row['table_name']][$row['record_id']] = true; + } + } + return isset($this->rtc['content'][$tableName][$identifier]); } - public function deleteAllByRecordTableAndRecordIdentifier(string $table, int $identifier): void + public function deleteAllByToken(string $token): void { $query = $this->connection->createQueryBuilder(); $query->delete(self::RUNNING_REQUEST_TABLE_NAME) - ->where($query->expr()->eq('table_name', $query->createNamedParameter($table))) - ->andWhere($query->expr()->eq('record_id', $query->createNamedParameter($identifier))) - ->execute(); + ->where($query->expr()->eq('request_token', $query->createNamedParameter($token))) + ->execute(); } protected function mapProperties(RunningRequest $runningRequest): array @@ -63,7 +58,7 @@ protected function mapProperties(RunningRequest $runningRequest): array 'record_id' => $runningRequest->getRecordId(), 'table_name' => $runningRequest->getTableName(), 'request_token' => $runningRequest->getRequestToken(), - 'timestamp_begin' => $runningRequest->getTimestampBegin() + 'timestamp_begin' => $runningRequest->getTimestampBegin(), ]; } } diff --git a/Classes/Domain/Service/Publishing/RunningRequestService.php b/Classes/Domain/Service/Publishing/RunningRequestService.php index 9b6cca95a..174fdfc1c 100644 --- a/Classes/Domain/Service/Publishing/RunningRequestService.php +++ b/Classes/Domain/Service/Publishing/RunningRequestService.php @@ -1,28 +1,67 @@ runningRequestRepository = $runningRequestRepository; } - /** - * @throws \Doctrine\DBAL\Exception - */ - public function isPublishingRequestRunningForThisRecord(int $identifier, string $tableName): bool + public function onRecordPublishingBegan(RecursiveRecordPublishingBegan $event): void + { + /** @var Record $record */ + $record = $event->getRecord(); + + $this->writeToRunningRequestsTable($record); + foreach ($record->getRelatedRecords() as $relatedRecords) { + foreach ($relatedRecords as $relatedRecord) { + $this->writeToRunningRequestsTable($relatedRecord); + } + } + } + + protected function writeToRunningRequestsTable(RecordInterface $record): void + { + $recordId = $record->getIdentifier(); + $tableName = $record->getTableName(); + $requestToken = $_REQUEST['token']; + + $runningRequest = new RunningRequest($recordId, $tableName, $requestToken); + $this->runningRequestRepository->add($runningRequest); + } + + public function onRecordPublishingEnded(RecursiveRecordPublishingEnded $event): void + { + $this->runningRequestRepository->deleteAllByToken($_REQUEST['token']); + } + + public function isPublishable(VoteIfRecordIsPublishable $event): void + { + if ($this->runningRequestRepository->hasRunningRequest($event->getIdentifier(), $event->getTable())) { + $event->voteNo(); + } + } + + public function isPublishing(DetermineIfRecordIsPublishing $event): void { - return $this->runningRequestRepository->existsRunningRequestForRecord($identifier, $tableName); + if ($this->runningRequestRepository->hasRunningRequest($event->getIdentifier(), $event->getTableName())) { + $event->setIsPublishing(); + } } } diff --git a/Classes/Event/DetermineIfRecordIsPublishing.php b/Classes/Event/DetermineIfRecordIsPublishing.php new file mode 100644 index 000000000..d5d70e2e5 --- /dev/null +++ b/Classes/Event/DetermineIfRecordIsPublishing.php @@ -0,0 +1,52 @@ +tableName = $tableName; + $this->identifier = $identifier; + } + + public function getTableName(): string + { + return $this->tableName; + } + + public function getIdentifier() + { + return $this->identifier; + } + + public function setIsPublishing(): void + { + $this->publishing = true; + } + + public function isPublishing(): bool + { + return $this->publishing; + } + + public function isPropagationStopped(): bool + { + return $this->publishing; + } +} diff --git a/Classes/EventListener/PublishingRequestIsRunningVoter.php b/Classes/EventListener/PublishingRequestIsRunningVoter.php deleted file mode 100644 index 239ca9b82..000000000 --- a/Classes/EventListener/PublishingRequestIsRunningVoter.php +++ /dev/null @@ -1,33 +0,0 @@ -runningRequestService = $runningRequestService; - } - - /** - * @throws \Doctrine\DBAL\Exception - */ - public function isPublishable(VoteIfRecordIsPublishable $event): void - { - $tableName = $event->getTable(); - $identifier = $event->getIdentifier(); - if ($this->runningRequestService->isPublishingRequestRunningForThisRecord($identifier, $tableName)) { - $event->voteNo(); - } else { - $event->voteYes(); - } - } -} diff --git a/Classes/EventListener/RecursivePublishingEndedListener.php b/Classes/EventListener/RecursivePublishingEndedListener.php deleted file mode 100644 index a4b19bb60..000000000 --- a/Classes/EventListener/RecursivePublishingEndedListener.php +++ /dev/null @@ -1,70 +0,0 @@ - - * Christine Zoglmeier - * - * 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! - */ - -use In2code\In2publishCore\Domain\Model\Record; -use In2code\In2publishCore\Domain\Repository\RunningRequestRepository; -use In2code\In2publishCore\Event\RecursiveRecordPublishingEnded; - -class RecursivePublishingEndedListener -{ - /** @var RunningRequestRepository */ - protected $runningRequestRepository; - - public function __construct(RunningRequestRepository $runningRequestRepository) - { - $this->runningRequestRepository = $runningRequestRepository; - } - public function onRecordPublishingEnded(RecursiveRecordPublishingEnded $event): void - { - /** @var Record $record */ - $record = $event->getRecord(); - - $this->deleteFromRunningRequestsTable($record); - foreach ($record->getRelatedRecords() as $tableName => $relatedRecords) { - foreach ($relatedRecords as $relatedRecord) { - $this->deleteFromRunningRequestsTable($relatedRecord); - } - } - } - - /** - * @param Record $record - * @return mixed - */ - protected function deleteFromRunningRequestsTable(Record $record) - { - $recordId = $record->getIdentifier(); - $tableName = $record->getTableName(); - - $this->runningRequestRepository->deleteAllByRecordTableAndRecordIdentifier($tableName, $recordId); - } -} diff --git a/Classes/EventListener/RecursivePublishingListener.php b/Classes/EventListener/RecursivePublishingListener.php deleted file mode 100644 index 38df54c26..000000000 --- a/Classes/EventListener/RecursivePublishingListener.php +++ /dev/null @@ -1,73 +0,0 @@ - - * Christine Zoglmeier - * - * 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! - */ - -use In2code\In2publishCore\Domain\Model\Record; -use In2code\In2publishCore\Domain\Model\RunningRequest; -use In2code\In2publishCore\Domain\Repository\RunningRequestRepository; -use In2code\In2publishCore\Event\RecursiveRecordPublishingBegan; - -class RecursivePublishingListener -{ - /** @var RunningRequestRepository */ - protected $runningRequestRepository; - - public function __construct(RunningRequestRepository $runningRequestRepository) - { - $this->runningRequestRepository = $runningRequestRepository; - } - public function onRecordPublishingBegan(RecursiveRecordPublishingBegan $event): void - { - /** @var Record $record */ - $record = $event->getRecord(); - - $this->writeToRunningRequestsTable($record); - foreach ($record->getRelatedRecords() as $tableName => $relatedRecords) { - foreach ($relatedRecords as $relatedRecord) { - $this->writeToRunningRequestsTable($relatedRecord); - } - } - } - - /** - * @param Record $record - * @return mixed - */ - protected function writeToRunningRequestsTable(Record $record) - { - $recordId = $record->getIdentifier(); - $tableName = $record->getTableName(); - $requestToken = $_REQUEST['token']; - - $runningRequest = new RunningRequest($recordId, $tableName, $requestToken); - $this->runningRequestRepository->add($runningRequest); - } -} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index b0b8038a1..a9beb0759 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -68,9 +68,6 @@ services: In2code\In2publishCore\Service\Permission\PermissionService: public: true - In2code\In2publishCore\Domain\Service\Publishing\RunningRequestService: - public: true - In2code\In2publishCore\Domain\Repository\TaskRepository: public: true @@ -103,23 +100,22 @@ services: method: 'onRootRecordCreationWasFinished' event: In2code\In2publishCore\Event\RootRecordCreationWasFinished - In2code\In2publishCore\EventListener\RecursivePublishingListener: + In2code\In2publishCore\Domain\Service\Publishing\RunningRequestService: tags: - name: event.listener - identifier: 'in2publishcore-recursivePublishingListener-recursiverecordpublishingbegan' + identifier: 'in2publishcore-RunningRequestService-RecursiveRecordPublishingBegan' method: 'onRecordPublishingBegan' event: In2code\In2publishCore\Event\RecursiveRecordPublishingBegan - - In2code\In2publishCore\EventListener\RecursivePublishingEndedListener: - tags: - name: event.listener - identifier: 'in2publishcore-recursivePublishingEndedListener-recursiverecordpublishingended' + identifier: 'in2publishcore-RunningRequestService-RecursiveRecordPublishingEnded' method: 'onRecordPublishingEnded' event: In2code\In2publishCore\Event\RecursiveRecordPublishingEnded - - In2code\In2publishCore\EventListener\PublishingRequestIsRunningVoter: - tags: - name: event.listener - identifier: 'in2publishcore-publishingRequestIsRunningVoter-VoteIfRecordIsPublishable' + identifier: 'in2publishcore-RunningRequestService-VoteIfRecordIsPublishable' method: 'isPublishable' event: In2code\In2publishCore\Event\VoteIfRecordIsPublishable + - name: event.listener + identifier: 'in2publishcore-RunningRequestService-DetermineIfRecordIsPublishing' + method: 'isPublishing' + event: In2code\In2publishCore\Event\DetermineIfRecordIsPublishing + From d81e8c75f4ec6130f1482797fb850e7a3af25568 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 13 Apr 2022 12:13:09 +0200 Subject: [PATCH 28/56] [BUGFIX] Position the publish link instead of just the icon, show publishing records Resolves: https://projekte.in2code.de/issues/49152 --- Resources/Private/Language/de.locallang.xlf | 8 +++++ Resources/Private/Language/locallang.xlf | 6 ++++ .../Private/Partials/File/Index/FileList.html | 31 +++++++++++++------ .../Partials/File/Index/FolderList.html | 1 + .../Partials/Record/Index/PageList.html | 27 +++++++++++----- Resources/Private/Sass/_Icons.scss | 31 +++++++++++-------- Resources/Private/Sass/_ModulesGeneral.scss | 2 +- Resources/Public/Css/Modules.css | 2 +- 8 files changed, 75 insertions(+), 33 deletions(-) diff --git a/Resources/Private/Language/de.locallang.xlf b/Resources/Private/Language/de.locallang.xlf index 5e94e8641..bbc003eb8 100755 --- a/Resources/Private/Language/de.locallang.xlf +++ b/Resources/Private/Language/de.locallang.xlf @@ -93,6 +93,14 @@ Publish this page Diese Seite publizieren + + This page is currently being published + Diese Seite wird gerade veröffentlicht + + + This file is currently being published + Diese Datei wird gerade veröffentlicht + Publish all files within folder "%s". Veröffentlichen aller Dateien innerhalb von "%s" diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index 3a1b27f17..7e00c4df5 100755 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -71,6 +71,12 @@ Publish this page + + This page is currently being published + + + This file is currently being published + Publish all files within folder "%s". diff --git a/Resources/Private/Partials/File/Index/FileList.html b/Resources/Private/Partials/File/Index/FileList.html index e7f69c681..c19be4bd2 100755 --- a/Resources/Private/Partials/File/Index/FileList.html +++ b/Resources/Private/Partials/File/Index/FileList.html @@ -8,16 +8,27 @@ [{record.additionalProperties.depth}] - - - - + + + + + + + + + + + + + diff --git a/Resources/Private/Partials/File/Index/FolderList.html b/Resources/Private/Partials/File/Index/FolderList.html index 9b0859a78..b0408bef5 100755 --- a/Resources/Private/Partials/File/Index/FolderList.html +++ b/Resources/Private/Partials/File/Index/FolderList.html @@ -11,6 +11,7 @@ diff --git a/Resources/Private/Partials/Record/Index/PageList.html b/Resources/Private/Partials/Record/Index/PageList.html index 0956184b0..799e39f44 100755 --- a/Resources/Private/Partials/Record/Index/PageList.html +++ b/Resources/Private/Partials/Record/Index/PageList.html @@ -13,14 +13,25 @@ [{record.additionalProperties.depth}] - - - - + + + + + + + + + + + + + diff --git a/Resources/Private/Sass/_Icons.scss b/Resources/Private/Sass/_Icons.scss index 6e65620a4..80e9a04a0 100644 --- a/Resources/Private/Sass/_Icons.scss +++ b/Resources/Private/Sass/_Icons.scss @@ -110,27 +110,32 @@ @extend .in2publish-icon-small; } -.in2publish-icon-publish { +.in2publish-link-publish { position: absolute; right: 0; top: 1px; - @extend .icon-arrow-right; - @extend .in2publish-icon-small; + &:hover { + text-decoration: none; + } - .in2publish-stagelisting__item__publish--blocked & { - right: 1px; - cursor: not-allowed; + .in2publish-icon-publish { + @extend .icon-arrow-right; + @extend .in2publish-icon-small; - &:before { - content: "\e60a"; - } - } + .in2publish-stagelisting__item__publish--blocked & { + right: 1px; + cursor: not-allowed; - .in2publish-stagelisting__item--removed & { + &:before { + content: "\e60a"; + } + } - &:hover { - color: $apple; + .in2publish-stagelisting__item--removed & { + &:hover { + color: $apple; + } } } } diff --git a/Resources/Private/Sass/_ModulesGeneral.scss b/Resources/Private/Sass/_ModulesGeneral.scss index cf235160c..67577c618 100644 --- a/Resources/Private/Sass/_ModulesGeneral.scss +++ b/Resources/Private/Sass/_ModulesGeneral.scss @@ -225,7 +225,7 @@ a.in2publish-notextdecoration { right: 25px + (12 * $n); } - .in2publish-icon-publish { + .in2publish-link-publish { right: 12px * $n; } diff --git a/Resources/Public/Css/Modules.css b/Resources/Public/Css/Modules.css index abcc56402..899ea0af3 100644 --- a/Resources/Public/Css/Modules.css +++ b/Resources/Public/Css/Modules.css @@ -1 +1 @@ -.in2publish-icon-info{position:absolute;top:1px;right:25px}.in2publish-icon-loop-alt4:before{font-size:90px !important;color:#5D9A46;position:absolute;top:25px;left:-45px}.in2publish-icon-loop-alt4.in2publish-warning:before{color:#FFCA4B}.in2publish-icon-loop-alt4.in2publish-connection-error:before{color:#A94442}.in2publish-icon-folder{margin:0 15px !important;position:relative;top:3px}.in2publish-icon-file{margin:0 15px;position:relative;top:3px}.in2publish-icon-publish{position:absolute;right:0;top:1px}.in2publish-stagelisting__item__publish--blocked .in2publish-icon-publish{right:1px;cursor:not-allowed}.in2publish-stagelisting__item__publish--blocked .in2publish-icon-publish:before{content:"\e60a"}.in2publish-stagelisting__item--removed .in2publish-icon-publish:hover{color:#5D9A46}@font-face{font-family:'in2publish';src:url("../Fonts/in2publish.eot?abcdef");src:url("../Fonts/in2publish.eot?#iefixabcdef") format("embedded-opentype"),url("../Fonts/in2publish.woff?abcdef") format("woff"),url("../Fonts/in2publish.ttf?abcdef") format("truetype"),url("../Fonts/in2publish.svg?abcdef#in2publish") format("svg");font-weight:normal;font-style:normal}[class^="in2publish-icon-"]:before,[class*=" in2publish-icon-"]:before,.in2publish-messages--removeable>.typo3-message:before{font-family:'in2publish';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;font-size:20px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-circle-o:before,.in2publish-icon-circle-o:before{content:"\f10c"}.icon-circle:before,.in2publish-icon-circle:before{content:"\f111"}.icon-blocked:before,.in2publish-icon-blocked:before{content:"\e60a"}.icon-x-altx-alt:before,.in2publish-icon-x-altx-alt:before{content:"\e609"}.icon-folder-download:before,.in2publish-icon-folder-download:before,.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e608"}.icon-history:before,.in2publish-icon-history:before{content:"\e603"}.icon-info:before,.in2publish-icon-info:before{content:"\e601"}.icon-loop-alt4:before,.in2publish-icon-loop-alt4:before{content:"\e600"}.icon-folder:before,.in2publish-icon-folder:before{content:"\e92f"}.icon-folder-open:before,.in2publish-icon-folder-open:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e930"}.icon-folder-plus:before,.in2publish-icon-folder-plus:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e931"}.icon-folder-minus:before,.in2publish-icon-folder-minus:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e932"}.icon-eye:before,.in2publish-icon-eye:before{content:"\e9ce"}.icon-arrow-right:before,.in2publish-icon-publish:before{content:"\ea34"}.icon-file-broken:before,.in2publish-icon-file-delete:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e604"}.icon-file-add:before,.in2publish-icon-file-add:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e605"}.icon-file-settings:before,.in2publish-icon-file-changed:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e606"}.icon-align-justify:before,.in2publish-icon-file:before{content:"\e607"}.icon-clock2:before{content:"\e60b"}.icon-edit:before,.in2publish-icon-edit:before{content:"\e602"}.nav-pills-container{background:white;padding:10px}div.typo3-fullDoc{height:auto}.in2publish-hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.in2publish-clearfix{zoom:1}.in2publish-clearfix:after{clear:both}.in2publish-clearfix:before,.in2publish-clearfix:after{content:"";display:table}.in2publish-icon-small:before,.in2publish-icon-history:before,.in2publish-icon-info:before,.in2publish-icon-eye:before,.in2publish-icon-edit:before,.in2publish-icon-publish:before{font-size:16px}.in2publish-unstyledlist{margin:0;padding:0;list-style-type:none}[data-action]{cursor:pointer}.in2publish-inline-block{display:inline-block}.in2publish-backend{font-size:15px;color:#fff}.in2publish-backend h1,.in2publish-backend h2,.in2publish-backend h3,.in2publish-backend h4,.in2publish-backend legend{color:#fff}.in2publish-backend select{color:#444}#typo3-docheader .in2publish-backend-select.module-docheader-bar{overflow:initial}.in2publish-backend *,.in2publish-backend *:before,.in2publish-backend *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.in2publish-backend ul{margin:0;padding:0}.in2publish-module>section{margin:15px 0}.in2publish-module>section>h3{margin-bottom:10px}.in2publish-module{background:#585858}legend{display:block;width:100%;padding:0;margin-bottom:18px;font-size:inherit;line-height:inherit;color:currentColor;border-style:none}label{font-weight:normal}a.in2publish-notextdecoration{text-decoration:none}.in2publish-main{margin-top:40px;overflow:hidden}.in2publish-container{overflow:hidden;margin:0 0 30px}.in2publish-container-50{position:relative;width:50%;float:left;text-align:center}.in2publish-container-50 img{width:90px;height:auto}.in2publish-stagelisting__item__column{background-color:#666;width:50%;float:left;height:30px;line-height:30px;position:relative;top:0;left:0}.in2publish-stagelisting__item__column a{color:#fff}.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column{background-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column{background-color:#A94442}.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column{background-color:#000}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column{background-color:#FFCA4B;color:#585858}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-publish,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-publish{color:#585858}.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column{background-color:#425ea1}.in2publish-list-level--1 .in2publish-icon-info{right:37px}.in2publish-list-level--1 .in2publish-icon-publish{right:12px}.in2publish-list-level--1 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:27px}.in2publish-list-level--2 .in2publish-icon-info{right:49px}.in2publish-list-level--2 .in2publish-icon-publish{right:24px}.in2publish-list-level--2 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:39px}.in2publish-list-level--3 .in2publish-icon-info{right:61px}.in2publish-list-level--3 .in2publish-icon-publish{right:36px}.in2publish-list-level--3 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:51px}.in2publish-list-level--4 .in2publish-icon-info{right:73px}.in2publish-list-level--4 .in2publish-icon-publish{right:48px}.in2publish-list-level--4 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:63px}.in2publish-list-level--5 .in2publish-icon-info{right:85px}.in2publish-list-level--5 .in2publish-icon-publish{right:60px}.in2publish-list-level--5 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:75px}.in2publish-backend .in2publish-list-level{margin:0 0 0 25px}.in2publish-backend .in2publish-list-level>li{border-top:1px solid #585858}.in2publish-stagelisting__dropdown{display:none;overflow:hidden;background-color:#DBDBDB;color:#585858;border:10px solid #666}.in2publish-stagelisting__dropdown a{color:currentColor}.in2publish-stagelisting__dropdown h3{background-color:#585858;font-weight:normal;font-size:1em;padding:0 15px;margin-top:0}.in2publish-stagelisting__dropdown h4{background-color:#666;font-style:italic;padding:3px 15px}.in2publish-stagelisting__dropdown li{list-style-type:none;padding:0 0 0 15px;word-break:break-all}.in2publish-stagelisting__dropdown [class^="in2publish-icon-"],.in2publish-stagelisting__dropdown [class*=" in2publish-icon-"]{padding:0 10px 0 0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown{border-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown{border-color:#A94442}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown{border-color:#FFCA4B}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown{border-color:#425ea1}.in2publish-stagelisting__dropdown--open{margin-bottom:10px}.in2publish-stagelisting__dropdown__item{width:50%;float:left;line-height:30px;padding:0}.in2publish-stagelisting__dropdown__item--full{width:100%}.in2publish-stagelisting__dropdown__item h3{line-height:30px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list>li{border-style:none;position:relative}.in2publish-stagelisting__dropdown__actions{padding:0 15px;background-color:#A0A0A0;color:#fff}.in2publish-stagelisting__dropdown__actions>a{margin-right:20px}.in2publish-stagelisting__dropdown__actions>a:last-child{margin-right:0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown__actions{background-color:#5D9A46}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown__actions{background-color:#C15955}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown__actions{background-color:#FFDB88;color:currentColor}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown__actions{background-color:#557AD1;color:#fff}.in2publish-stagelisting__dropdown__page{background-color:#fff}.in2publish-backend .in2publish-related__title{font-style:normal;line-height:30px;padding:0 15px;margin:0;background-color:#FFDB88;color:#444}.in2publish-backend .in2publish-related__list{margin:12px 0 15px}.in2publish-backend .in2publish-related__list li{font-size:14px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list{margin-bottom:12px}.in2publish-footer{margin:20px 0;color:#A0A0A0;font-size:80%}.in2publish-footer .in2publish-logo{float:right;width:160px;height:48px}.in2publish-functions-bar{background-color:#666;margin:20px 0;text-align:center;position:relative;padding:15px;min-height:73px}.in2publish-functions-bar__filter{position:absolute;right:20px;top:22px}.in2publish-functions-bar__filter i:before{font-size:30px}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link{display:inline-block;margin:0 0 0 10px;color:#fff}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link:hover{text-decoration:none}.in2publish-functions-bar__filter .in2publish-functions-bar--active{border-bottom:2px solid #fff}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-changed{border-color:#FFCA4B}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-added{border-color:#5D9A46}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-deleted{border-color:#A94442}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-moved{border-color:#557AD1}.in2publish-preloader{background-color:#585858;height:100%;position:fixed;z-index:100000;text-align:center;opacity:0.9;top:0;left:0;right:0;bottom:0}.in2publish-preloader--hidden{display:none}.in2publish-preloader--spinner{position:relative;top:30%;margin:100px auto;width:50px;height:30px;text-align:center;font-size:10px}.in2publish-preloader--spinner>div{background-color:#fff;height:100%;width:6px;display:inline-block;-webkit-animation:stretchdelay 1.2s infinite ease-in-out;animation:stretchdelay 1.2s infinite ease-in-out}.in2publish-preloader--spinner .rect2{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.in2publish-preloader--spinner .rect3{-webkit-animation-delay:-1.0s;animation-delay:-1.0s}.in2publish-preloader--spinner .rect4{-webkit-animation-delay:-0.9s;animation-delay:-0.9s}.in2publish-preloader--spinner .rect5{-webkit-animation-delay:-0.8s;animation-delay:-0.8s}div#typo3-docbody.stopScrolling{transform:none}@-webkit-keyframes stretchdelay{0%, 40%, 100%{-webkit-transform:scaleY(0.4)}20%{-webkit-transform:scaleY(1)}}@keyframes stretchdelay{0%, 40%, 100%{transform:scaleY(0.4);-webkit-transform:scaleY(0.4)}20%{transform:scaleY(1);-webkit-transform:scaleY(1)}}.in2publish-removevalue:before{right:4px;bottom:4px} +.in2publish-icon-info{position:absolute;top:1px;right:25px}.in2publish-icon-loop-alt4:before{font-size:90px !important;color:#5D9A46;position:absolute;top:25px;left:-45px}.in2publish-icon-loop-alt4.in2publish-warning:before{color:#FFCA4B}.in2publish-icon-loop-alt4.in2publish-connection-error:before{color:#A94442}.in2publish-icon-folder{margin:0 15px !important;position:relative;top:3px}.in2publish-icon-file{margin:0 15px;position:relative;top:3px}.in2publish-link-publish{position:absolute;right:0;top:1px}.in2publish-link-publish:hover{text-decoration:none}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish{right:1px;cursor:not-allowed}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish:before{content:"\e60a"}.in2publish-stagelisting__item--removed .in2publish-link-publish .in2publish-icon-publish:hover{color:#5D9A46}@font-face{font-family:'in2publish';src:url("../Fonts/in2publish.eot?abcdef");src:url("../Fonts/in2publish.eot?#iefixabcdef") format("embedded-opentype"),url("../Fonts/in2publish.woff?abcdef") format("woff"),url("../Fonts/in2publish.ttf?abcdef") format("truetype"),url("../Fonts/in2publish.svg?abcdef#in2publish") format("svg");font-weight:normal;font-style:normal}[class^="in2publish-icon-"]:before,[class*=" in2publish-icon-"]:before,.in2publish-messages--removeable>.typo3-message:before{font-family:'in2publish';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;font-size:20px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-circle-o:before,.in2publish-icon-circle-o:before{content:"\f10c"}.icon-circle:before,.in2publish-icon-circle:before{content:"\f111"}.icon-blocked:before,.in2publish-icon-blocked:before{content:"\e60a"}.icon-x-altx-alt:before,.in2publish-icon-x-altx-alt:before{content:"\e609"}.icon-folder-download:before,.in2publish-icon-folder-download:before,.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e608"}.icon-history:before,.in2publish-icon-history:before{content:"\e603"}.icon-info:before,.in2publish-icon-info:before{content:"\e601"}.icon-loop-alt4:before,.in2publish-icon-loop-alt4:before{content:"\e600"}.icon-folder:before,.in2publish-icon-folder:before{content:"\e92f"}.icon-folder-open:before,.in2publish-icon-folder-open:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e930"}.icon-folder-plus:before,.in2publish-icon-folder-plus:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e931"}.icon-folder-minus:before,.in2publish-icon-folder-minus:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e932"}.icon-eye:before,.in2publish-icon-eye:before{content:"\e9ce"}.icon-arrow-right:before,.in2publish-link-publish .in2publish-icon-publish:before{content:"\ea34"}.icon-file-broken:before,.in2publish-icon-file-delete:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e604"}.icon-file-add:before,.in2publish-icon-file-add:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e605"}.icon-file-settings:before,.in2publish-icon-file-changed:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e606"}.icon-align-justify:before,.in2publish-icon-file:before{content:"\e607"}.icon-clock2:before{content:"\e60b"}.icon-edit:before,.in2publish-icon-edit:before{content:"\e602"}.nav-pills-container{background:white;padding:10px}div.typo3-fullDoc{height:auto}.in2publish-hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.in2publish-clearfix{zoom:1}.in2publish-clearfix:after{clear:both}.in2publish-clearfix:before,.in2publish-clearfix:after{content:"";display:table}.in2publish-icon-small:before,.in2publish-icon-history:before,.in2publish-icon-info:before,.in2publish-icon-eye:before,.in2publish-icon-edit:before,.in2publish-link-publish .in2publish-icon-publish:before{font-size:16px}.in2publish-unstyledlist{margin:0;padding:0;list-style-type:none}[data-action]{cursor:pointer}.in2publish-inline-block{display:inline-block}.in2publish-backend{font-size:15px;color:#fff}.in2publish-backend h1,.in2publish-backend h2,.in2publish-backend h3,.in2publish-backend h4,.in2publish-backend legend{color:#fff}.in2publish-backend select{color:#444}#typo3-docheader .in2publish-backend-select.module-docheader-bar{overflow:initial}.in2publish-backend *,.in2publish-backend *:before,.in2publish-backend *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.in2publish-backend ul{margin:0;padding:0}.in2publish-module>section{margin:15px 0}.in2publish-module>section>h3{margin-bottom:10px}.in2publish-module{background:#585858}legend{display:block;width:100%;padding:0;margin-bottom:18px;font-size:inherit;line-height:inherit;color:currentColor;border-style:none}label{font-weight:normal}a.in2publish-notextdecoration{text-decoration:none}.in2publish-main{margin-top:40px;overflow:hidden}.in2publish-container{overflow:hidden;margin:0 0 30px}.in2publish-container-50{position:relative;width:50%;float:left;text-align:center}.in2publish-container-50 img{width:90px;height:auto}.in2publish-stagelisting__item__column{background-color:#666;width:50%;float:left;height:30px;line-height:30px;position:relative;top:0;left:0}.in2publish-stagelisting__item__column a{color:#fff}.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column{background-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column{background-color:#A94442}.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column{background-color:#000}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column{background-color:#FFCA4B;color:#585858}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-publish,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-publish{color:#585858}.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column{background-color:#425ea1}.in2publish-list-level--1 .in2publish-icon-info{right:37px}.in2publish-list-level--1 .in2publish-link-publish{right:12px}.in2publish-list-level--1 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:27px}.in2publish-list-level--2 .in2publish-icon-info{right:49px}.in2publish-list-level--2 .in2publish-link-publish{right:24px}.in2publish-list-level--2 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:39px}.in2publish-list-level--3 .in2publish-icon-info{right:61px}.in2publish-list-level--3 .in2publish-link-publish{right:36px}.in2publish-list-level--3 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:51px}.in2publish-list-level--4 .in2publish-icon-info{right:73px}.in2publish-list-level--4 .in2publish-link-publish{right:48px}.in2publish-list-level--4 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:63px}.in2publish-list-level--5 .in2publish-icon-info{right:85px}.in2publish-list-level--5 .in2publish-link-publish{right:60px}.in2publish-list-level--5 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:75px}.in2publish-backend .in2publish-list-level{margin:0 0 0 25px}.in2publish-backend .in2publish-list-level>li{border-top:1px solid #585858}.in2publish-stagelisting__dropdown{display:none;overflow:hidden;background-color:#DBDBDB;color:#585858;border:10px solid #666}.in2publish-stagelisting__dropdown a{color:currentColor}.in2publish-stagelisting__dropdown h3{background-color:#585858;font-weight:normal;font-size:1em;padding:0 15px;margin-top:0}.in2publish-stagelisting__dropdown h4{background-color:#666;font-style:italic;padding:3px 15px}.in2publish-stagelisting__dropdown li{list-style-type:none;padding:0 0 0 15px;word-break:break-all}.in2publish-stagelisting__dropdown [class^="in2publish-icon-"],.in2publish-stagelisting__dropdown [class*=" in2publish-icon-"]{padding:0 10px 0 0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown{border-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown{border-color:#A94442}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown{border-color:#FFCA4B}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown{border-color:#425ea1}.in2publish-stagelisting__dropdown--open{margin-bottom:10px}.in2publish-stagelisting__dropdown__item{width:50%;float:left;line-height:30px;padding:0}.in2publish-stagelisting__dropdown__item--full{width:100%}.in2publish-stagelisting__dropdown__item h3{line-height:30px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list>li{border-style:none;position:relative}.in2publish-stagelisting__dropdown__actions{padding:0 15px;background-color:#A0A0A0;color:#fff}.in2publish-stagelisting__dropdown__actions>a{margin-right:20px}.in2publish-stagelisting__dropdown__actions>a:last-child{margin-right:0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown__actions{background-color:#5D9A46}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown__actions{background-color:#C15955}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown__actions{background-color:#FFDB88;color:currentColor}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown__actions{background-color:#557AD1;color:#fff}.in2publish-stagelisting__dropdown__page{background-color:#fff}.in2publish-backend .in2publish-related__title{font-style:normal;line-height:30px;padding:0 15px;margin:0;background-color:#FFDB88;color:#444}.in2publish-backend .in2publish-related__list{margin:12px 0 15px}.in2publish-backend .in2publish-related__list li{font-size:14px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list{margin-bottom:12px}.in2publish-footer{margin:20px 0;color:#A0A0A0;font-size:80%}.in2publish-footer .in2publish-logo{float:right;width:160px;height:48px}.in2publish-functions-bar{background-color:#666;margin:20px 0;text-align:center;position:relative;padding:15px;min-height:73px}.in2publish-functions-bar__filter{position:absolute;right:20px;top:22px}.in2publish-functions-bar__filter i:before{font-size:30px}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link{display:inline-block;margin:0 0 0 10px;color:#fff}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link:hover{text-decoration:none}.in2publish-functions-bar__filter .in2publish-functions-bar--active{border-bottom:2px solid #fff}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-changed{border-color:#FFCA4B}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-added{border-color:#5D9A46}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-deleted{border-color:#A94442}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-moved{border-color:#557AD1}.in2publish-preloader{background-color:#585858;height:100%;position:fixed;z-index:100000;text-align:center;opacity:0.9;top:0;left:0;right:0;bottom:0}.in2publish-preloader--hidden{display:none}.in2publish-preloader--spinner{position:relative;top:30%;margin:100px auto;width:50px;height:30px;text-align:center;font-size:10px}.in2publish-preloader--spinner>div{background-color:#fff;height:100%;width:6px;display:inline-block;-webkit-animation:stretchdelay 1.2s infinite ease-in-out;animation:stretchdelay 1.2s infinite ease-in-out}.in2publish-preloader--spinner .rect2{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.in2publish-preloader--spinner .rect3{-webkit-animation-delay:-1.0s;animation-delay:-1.0s}.in2publish-preloader--spinner .rect4{-webkit-animation-delay:-0.9s;animation-delay:-0.9s}.in2publish-preloader--spinner .rect5{-webkit-animation-delay:-0.8s;animation-delay:-0.8s}div#typo3-docbody.stopScrolling{transform:none}@-webkit-keyframes stretchdelay{0%, 40%, 100%{-webkit-transform:scaleY(0.4)}20%{-webkit-transform:scaleY(1)}}@keyframes stretchdelay{0%, 40%, 100%{transform:scaleY(0.4);-webkit-transform:scaleY(0.4)}20%{transform:scaleY(1);-webkit-transform:scaleY(1)}}.in2publish-removevalue:before{right:4px;bottom:4px} From e30ea7b19a5c0389d53796440d00df4382b1ded7 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Thu, 14 Apr 2022 10:02:28 +0200 Subject: [PATCH 29/56] [BUGFIX] Replace publishing finished event with shutdown function This ensures that the "record is publishing" information is deleted even if an exception occurs. Resolves: https://projekte.in2code.de/issues/49152 --- .../Publishing/RunningRequestService.php | 22 +++++++++++++------ Configuration/Services.yaml | 5 ----- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Classes/Domain/Service/Publishing/RunningRequestService.php b/Classes/Domain/Service/Publishing/RunningRequestService.php index 174fdfc1c..52bd562a5 100644 --- a/Classes/Domain/Service/Publishing/RunningRequestService.php +++ b/Classes/Domain/Service/Publishing/RunningRequestService.php @@ -10,14 +10,18 @@ use In2code\In2publishCore\Domain\Repository\RunningRequestRepository; use In2code\In2publishCore\Event\DetermineIfRecordIsPublishing; use In2code\In2publishCore\Event\RecursiveRecordPublishingBegan; -use In2code\In2publishCore\Event\RecursiveRecordPublishingEnded; use In2code\In2publishCore\Event\VoteIfRecordIsPublishable; +use TYPO3\CMS\Core\SingletonInterface; -class RunningRequestService +use function register_shutdown_function; + +class RunningRequestService implements SingletonInterface { /** @var RunningRequestRepository */ protected $runningRequestRepository; + protected $shutdownFunctionRegistered = false; + public function __construct(RunningRequestRepository $runningRequestRepository) { $this->runningRequestRepository = $runningRequestRepository; @@ -25,6 +29,15 @@ public function __construct(RunningRequestRepository $runningRequestRepository) public function onRecordPublishingBegan(RecursiveRecordPublishingBegan $event): void { + if (!$this->shutdownFunctionRegistered) { + $repository = $this->runningRequestRepository; + $token = $_REQUEST['token']; + register_shutdown_function(static function () use ($repository, $token) { + $repository->deleteAllByToken($token); + }); + $this->shutdownFunctionRegistered = true; + } + /** @var Record $record */ $record = $event->getRecord(); @@ -46,11 +59,6 @@ protected function writeToRunningRequestsTable(RecordInterface $record): void $this->runningRequestRepository->add($runningRequest); } - public function onRecordPublishingEnded(RecursiveRecordPublishingEnded $event): void - { - $this->runningRequestRepository->deleteAllByToken($_REQUEST['token']); - } - public function isPublishable(VoteIfRecordIsPublishable $event): void { if ($this->runningRequestRepository->hasRunningRequest($event->getIdentifier(), $event->getTable())) { diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index a9beb0759..8c6fc996c 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -106,10 +106,6 @@ services: identifier: 'in2publishcore-RunningRequestService-RecursiveRecordPublishingBegan' method: 'onRecordPublishingBegan' event: In2code\In2publishCore\Event\RecursiveRecordPublishingBegan - - name: event.listener - identifier: 'in2publishcore-RunningRequestService-RecursiveRecordPublishingEnded' - method: 'onRecordPublishingEnded' - event: In2code\In2publishCore\Event\RecursiveRecordPublishingEnded - name: event.listener identifier: 'in2publishcore-RunningRequestService-VoteIfRecordIsPublishable' method: 'isPublishable' @@ -118,4 +114,3 @@ services: identifier: 'in2publishcore-RunningRequestService-DetermineIfRecordIsPublishing' method: 'isPublishing' event: In2code\In2publishCore\Event\DetermineIfRecordIsPublishing - From 5d576a214abaac6d11fb4b658de98f017c0a2929 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 10:48:14 +0200 Subject: [PATCH 30/56] [BUGFIX] Set Records as not publishable if they are already publishing Resolves: https://projekte.in2code.de/issues/50387 --- Classes/Domain/Model/Record.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Classes/Domain/Model/Record.php b/Classes/Domain/Model/Record.php index 96bd0c919..4b625a58b 100755 --- a/Classes/Domain/Model/Record.php +++ b/Classes/Domain/Model/Record.php @@ -1153,6 +1153,9 @@ public function isPublishable(): bool if (!$this->isChangedRecursive()) { return false; } + if ($this->isPublishing()) { + return false; + } $permissionService = GeneralUtility::makeInstance(PermissionService::class); if (!$permissionService->isUserAllowedToPublish()) { From 7a3b35c3902cfba869c0c6c940adb3fefc8cf574 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 10:48:58 +0200 Subject: [PATCH 31/56] [BUGFIX] Use a random token to identify a request instead of the BE user token Resolves: https://projekte.in2code.de/issues/50387 --- .../Service/Publishing/RunningRequestService.php | 10 +++++++--- ext_tables.sql | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Classes/Domain/Service/Publishing/RunningRequestService.php b/Classes/Domain/Service/Publishing/RunningRequestService.php index 52bd562a5..9855805df 100644 --- a/Classes/Domain/Service/Publishing/RunningRequestService.php +++ b/Classes/Domain/Service/Publishing/RunningRequestService.php @@ -13,6 +13,8 @@ use In2code\In2publishCore\Event\VoteIfRecordIsPublishable; use TYPO3\CMS\Core\SingletonInterface; +use function bin2hex; +use function random_bytes; use function register_shutdown_function; class RunningRequestService implements SingletonInterface @@ -20,18 +22,21 @@ class RunningRequestService implements SingletonInterface /** @var RunningRequestRepository */ protected $runningRequestRepository; + protected $requestToken; + protected $shutdownFunctionRegistered = false; public function __construct(RunningRequestRepository $runningRequestRepository) { $this->runningRequestRepository = $runningRequestRepository; + $this->requestToken = bin2hex(random_bytes(16)); } public function onRecordPublishingBegan(RecursiveRecordPublishingBegan $event): void { if (!$this->shutdownFunctionRegistered) { $repository = $this->runningRequestRepository; - $token = $_REQUEST['token']; + $token = $this->requestToken; register_shutdown_function(static function () use ($repository, $token) { $repository->deleteAllByToken($token); }); @@ -53,9 +58,8 @@ protected function writeToRunningRequestsTable(RecordInterface $record): void { $recordId = $record->getIdentifier(); $tableName = $record->getTableName(); - $requestToken = $_REQUEST['token']; - $runningRequest = new RunningRequest($recordId, $tableName, $requestToken); + $runningRequest = new RunningRequest($recordId, $tableName, $this->requestToken); $this->runningRequestRepository->add($runningRequest); } diff --git a/ext_tables.sql b/ext_tables.sql index e1c74a2cd..5583d61ec 100755 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -35,7 +35,7 @@ CREATE TABLE tx_in2publishcore_running_request record_id int(11) unsigned NOT NULL, table_name varchar(255) DEFAULT '' NOT NULL, - request_token varchar(255) DEFAULT '' NOT NULL, + request_token char(32) DEFAULT '' NOT NULL, timestamp_begin int(11) unsigned DEFAULT '0' NOT NULL, PRIMARY KEY (uid) From 41795ae20a55d43874422d4e03968012851ca7cf Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 10:49:36 +0200 Subject: [PATCH 32/56] [BUGFIX] Show the publish loader if redirects are publishing Resolves: https://projekte.in2code.de/issues/50387 --- .../RedirectsSupport/Domain/Model/SysRedirect.php | 9 +++++++++ Resources/Private/Templates/Redirect/List.html | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/Classes/Features/RedirectsSupport/Domain/Model/SysRedirect.php b/Classes/Features/RedirectsSupport/Domain/Model/SysRedirect.php index 005b8fd2d..01a5fb186 100644 --- a/Classes/Features/RedirectsSupport/Domain/Model/SysRedirect.php +++ b/Classes/Features/RedirectsSupport/Domain/Model/SysRedirect.php @@ -31,8 +31,11 @@ use In2code\In2publishCore\Component\RecordHandling\RecordFinder; use In2code\In2publishCore\Domain\Model\RecordInterface; +use In2code\In2publishCore\Domain\Service\Publishing\RunningRequestService; +use In2code\In2publishCore\Event\DetermineIfRecordIsPublishing; use In2code\In2publishCore\Service\Configuration\TcaService; use In2code\In2publishCore\Service\Database\RawRecordService; +use TYPO3\CMS\Core\EventDispatcher\EventDispatcher; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; @@ -157,6 +160,12 @@ public function getRecord(): RecordInterface public function getPublishingState(): string { + $event = new DetermineIfRecordIsPublishing('sys_redirect', $this->uid); + $eventDispatcher = GeneralUtility::makeInstance(EventDispatcher::class); + $eventDispatcher->dispatch($event); + if ($event->isPublishing()) { + return 'publishing'; + } $record = $this->getRecord(); if (!$record->isChanged()) { // Nothing to publish diff --git a/Resources/Private/Templates/Redirect/List.html b/Resources/Private/Templates/Redirect/List.html index 572128b2c..f6ee3db0d 100644 --- a/Resources/Private/Templates/Redirect/List.html +++ b/Resources/Private/Templates/Redirect/List.html @@ -79,6 +79,11 @@ + + + + + From b97ed3bbcad5d2a995288888105c2b6093bd1418 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 10:50:02 +0200 Subject: [PATCH 33/56] [BUGFIX] Move closing quote to the line it belongs Related: https://projekte.in2code.de/issues/50387 --- Resources/Private/Partials/File/Index/FileList.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Private/Partials/File/Index/FileList.html b/Resources/Private/Partials/File/Index/FileList.html index c19be4bd2..2cc7b666c 100755 --- a/Resources/Private/Partials/File/Index/FileList.html +++ b/Resources/Private/Partials/File/Index/FileList.html @@ -22,8 +22,8 @@ arguments="{ uid:record.identifier, identifier:'{publish:record.getMergedProperty(record:record, propertyName: \'identifier\')}', - storage:'{publish:record.getMergedProperty(record:record, propertyName: \'storage\')} - '}" + storage:'{publish:record.getMergedProperty(record:record, propertyName: \'storage\')}' + }" additionalAttributes="{data-in2publish-overlay: 'TRUE', data-in2publish-confirm: '{f:translate(key:\'confirm_publish_file\', default:\'Are you sure?\')}'}"> From 49ee66476dc575c6a2da36b02a9ade99102429c8 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 10:50:42 +0200 Subject: [PATCH 34/56] [FEATURE] Add RegisterViewHelper to set variables in templates that survive scope popping Related: https://projekte.in2code.de/issues/50387 --- Classes/ViewHelpers/RegisterViewHelper.php | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Classes/ViewHelpers/RegisterViewHelper.php diff --git a/Classes/ViewHelpers/RegisterViewHelper.php b/Classes/ViewHelpers/RegisterViewHelper.php new file mode 100644 index 000000000..8a9f6aa68 --- /dev/null +++ b/Classes/ViewHelpers/RegisterViewHelper.php @@ -0,0 +1,48 @@ + + * + * Example get a value: + * registerArgument('name', 'string', 'Name of the register', true); + $this->registerArgument('value', 'mixed', 'Value to set or omit to retrieve', false, self::VALUE_NONE); + } + + /** + * @return mixed + */ + public function render() + { + /** @var string $name */ + $name = $this->arguments['name']; + $value = $this->arguments['value']; + + if ($value !== self::VALUE_NONE) { + $this->register[$name] = $value; + } + return $this->register[$name] ?? null; + } +} From 0b3fa1d541f50b679640ff2375bb0418826e88d0 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 11:16:30 +0200 Subject: [PATCH 35/56] [BUGFIX] Use count instead of select to count scheduler task rowsrows Resolves: https://projekte.in2code.de/issues/50387 --- .../Database/TableGarbageCollectorTest.php | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php index e635da0fb..6a71965a1 100644 --- a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php +++ b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php @@ -1,9 +1,9 @@ createQueryBuilder(); - $statement = $query->select('*') - ->from('tx_scheduler_task') - ->where($query->expr()->like( - 'serialized_task_object', - $query->createNamedParameter('%tx_in2publishcore_running_request%')) - ) - ->execute(); - $garbageCollectionTasksExists = $statement->rowCount() > 0; - - if ($garbageCollectionTasksExists == false) { + $query->count('*') + ->from('tx_scheduler_task') + ->where( + $query->expr()->like( + 'serialized_task_object', + $query->createNamedParameter('%tx_in2publishcore_running_request%') + ) + ); + $statement = $query->execute(); + + if (0 === $statement->fetchColumn()) { return new TestResult( 'database.garbage_collector_task_missing', TestResult::ERROR From c36650ad13b8912b2a76ca1dd1c070c37437c858 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 15:14:17 +0200 Subject: [PATCH 36/56] [BUGFIX] Remove condition around garbage collector configuration It is never necessary --- ext_localconf.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ext_localconf.php b/ext_localconf.php index 63bf615dc..44f1d24aa 100755 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -100,14 +100,14 @@ [\In2code\In2publishCore\Controller\FrontendController::class => 'preview'], [\In2code\In2publishCore\Controller\FrontendController::class => 'preview'] ); + /******************************************** Configure Garbage Collector ****************************************/ // Register table tx_in2publishcore_running_request in table garbage collector - if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\TableGarbageCollectionTask::class]['options']['tables']['tx_in2publishcore_running_request'])) { - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\TableGarbageCollectionTask::class]['options']['tables']['tx_in2publishcore_running_request'] = [ - 'dateField' => 'timestamp_begin', - 'expirePeriod' => 1, - ]; - } + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\TableGarbageCollectionTask::class]['options']['tables']['tx_in2publishcore_running_request'] = [ + 'dateField' => 'timestamp_begin', + 'expirePeriod' => 1, + ]; + /***************************************** Register Communication Adapter *****************************************/ $adapterRegistry->registerAdapter( \In2code\In2publishCore\Communication\RemoteCommandExecution\RemoteAdapter\SshAdapter::ADAPTER_TYPE, From 2cb3efd322fe42dd423cf48b4a4fce9ecb2270ba Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Wed, 20 Apr 2022 15:47:54 +0200 Subject: [PATCH 37/56] [BUGFIX] Only check for publishing processes running in other processes --- Classes/Domain/Repository/RunningRequestRepository.php | 10 +++++++--- .../Service/Publishing/RunningRequestService.php | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Classes/Domain/Repository/RunningRequestRepository.php b/Classes/Domain/Repository/RunningRequestRepository.php index 0fec5e243..fcb41ea84 100644 --- a/Classes/Domain/Repository/RunningRequestRepository.php +++ b/Classes/Domain/Repository/RunningRequestRepository.php @@ -33,11 +33,15 @@ public function add(RunningRequest $runningRequest): void /** * @param int|string $identifier */ - public function hasRunningRequest($identifier, string $tableName): bool + public function isPublishingInDifferentRequest($identifier, string $tableName, string $token): bool { if (!isset($this->rtc['content'])) { - $rows = $this->connection->select(['*'], self::RUNNING_REQUEST_TABLE_NAME); - foreach ($rows as $row) { + $query = $this->connection->createQueryBuilder(); + $query->select('*') + ->from(self::RUNNING_REQUEST_TABLE_NAME) + ->where($query->expr()->neq('request_token', $query->createNamedParameter($token))); + $result = $query->execute(); + foreach ($result->fetchAll() as $row) { $this->rtc['content'][$row['table_name']][$row['record_id']] = true; } } diff --git a/Classes/Domain/Service/Publishing/RunningRequestService.php b/Classes/Domain/Service/Publishing/RunningRequestService.php index 9855805df..41b31b10f 100644 --- a/Classes/Domain/Service/Publishing/RunningRequestService.php +++ b/Classes/Domain/Service/Publishing/RunningRequestService.php @@ -65,14 +65,18 @@ protected function writeToRunningRequestsTable(RecordInterface $record): void public function isPublishable(VoteIfRecordIsPublishable $event): void { - if ($this->runningRequestRepository->hasRunningRequest($event->getIdentifier(), $event->getTable())) { + $id = $event->getIdentifier(); + $table = $event->getTable(); + if ($this->runningRequestRepository->isPublishingInDifferentRequest($id, $table, $this->requestToken)) { $event->voteNo(); } } public function isPublishing(DetermineIfRecordIsPublishing $event): void { - if ($this->runningRequestRepository->hasRunningRequest($event->getIdentifier(), $event->getTableName())) { + $id = $event->getIdentifier(); + $table = $event->getTableName(); + if ($this->runningRequestRepository->isPublishingInDifferentRequest($id, $table, $this->requestToken)) { $event->setIsPublishing(); } } From 6f36ef01b9e919e8c4c5ed6dcb07f1122de9088d Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Thu, 21 Apr 2022 13:11:29 +0200 Subject: [PATCH 38/56] [BUGFIX] Use a static property, because ViewHelper Singletons don't work --- Classes/ViewHelpers/RegisterViewHelper.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Classes/ViewHelpers/RegisterViewHelper.php b/Classes/ViewHelpers/RegisterViewHelper.php index 8a9f6aa68..e47072355 100644 --- a/Classes/ViewHelpers/RegisterViewHelper.php +++ b/Classes/ViewHelpers/RegisterViewHelper.php @@ -4,7 +4,6 @@ namespace In2code\In2publishCore\ViewHelpers; -use TYPO3\CMS\Core\SingletonInterface; use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper; /** @@ -18,12 +17,12 @@ * Example get a value: * arguments['value']; if ($value !== self::VALUE_NONE) { - $this->register[$name] = $value; + self::$register[$name] = $value; } - return $this->register[$name] ?? null; + return self::$register[$name] ?? null; } } From 3815efa6a79d9a5c363841fb9c3fbf72897c29b0 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Fri, 22 Apr 2022 11:25:34 +0200 Subject: [PATCH 39/56] [BUGFIX] Ensure all links in the publish overview mod in yellow rows are black --- Resources/Private/Sass/_ModulesGeneral.scss | 3 ++- Resources/Public/Css/Modules.css | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Resources/Private/Sass/_ModulesGeneral.scss b/Resources/Private/Sass/_ModulesGeneral.scss index 67577c618..1ae968865 100644 --- a/Resources/Private/Sass/_ModulesGeneral.scss +++ b/Resources/Private/Sass/_ModulesGeneral.scss @@ -175,6 +175,7 @@ a.in2publish-notextdecoration { .in2publish-icon-file { @extend .icon-file-broken; } + } .in2publish-stagelisting__item--removed & { @@ -202,7 +203,7 @@ a.in2publish-notextdecoration { @extend .icon-file-settings; } - .in2publish-icon-publish { + a { color: $scorpion; } } diff --git a/Resources/Public/Css/Modules.css b/Resources/Public/Css/Modules.css index 899ea0af3..5979f9adc 100644 --- a/Resources/Public/Css/Modules.css +++ b/Resources/Public/Css/Modules.css @@ -1 +1 @@ -.in2publish-icon-info{position:absolute;top:1px;right:25px}.in2publish-icon-loop-alt4:before{font-size:90px !important;color:#5D9A46;position:absolute;top:25px;left:-45px}.in2publish-icon-loop-alt4.in2publish-warning:before{color:#FFCA4B}.in2publish-icon-loop-alt4.in2publish-connection-error:before{color:#A94442}.in2publish-icon-folder{margin:0 15px !important;position:relative;top:3px}.in2publish-icon-file{margin:0 15px;position:relative;top:3px}.in2publish-link-publish{position:absolute;right:0;top:1px}.in2publish-link-publish:hover{text-decoration:none}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish{right:1px;cursor:not-allowed}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish:before{content:"\e60a"}.in2publish-stagelisting__item--removed .in2publish-link-publish .in2publish-icon-publish:hover{color:#5D9A46}@font-face{font-family:'in2publish';src:url("../Fonts/in2publish.eot?abcdef");src:url("../Fonts/in2publish.eot?#iefixabcdef") format("embedded-opentype"),url("../Fonts/in2publish.woff?abcdef") format("woff"),url("../Fonts/in2publish.ttf?abcdef") format("truetype"),url("../Fonts/in2publish.svg?abcdef#in2publish") format("svg");font-weight:normal;font-style:normal}[class^="in2publish-icon-"]:before,[class*=" in2publish-icon-"]:before,.in2publish-messages--removeable>.typo3-message:before{font-family:'in2publish';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;font-size:20px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-circle-o:before,.in2publish-icon-circle-o:before{content:"\f10c"}.icon-circle:before,.in2publish-icon-circle:before{content:"\f111"}.icon-blocked:before,.in2publish-icon-blocked:before{content:"\e60a"}.icon-x-altx-alt:before,.in2publish-icon-x-altx-alt:before{content:"\e609"}.icon-folder-download:before,.in2publish-icon-folder-download:before,.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e608"}.icon-history:before,.in2publish-icon-history:before{content:"\e603"}.icon-info:before,.in2publish-icon-info:before{content:"\e601"}.icon-loop-alt4:before,.in2publish-icon-loop-alt4:before{content:"\e600"}.icon-folder:before,.in2publish-icon-folder:before{content:"\e92f"}.icon-folder-open:before,.in2publish-icon-folder-open:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e930"}.icon-folder-plus:before,.in2publish-icon-folder-plus:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e931"}.icon-folder-minus:before,.in2publish-icon-folder-minus:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e932"}.icon-eye:before,.in2publish-icon-eye:before{content:"\e9ce"}.icon-arrow-right:before,.in2publish-link-publish .in2publish-icon-publish:before{content:"\ea34"}.icon-file-broken:before,.in2publish-icon-file-delete:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e604"}.icon-file-add:before,.in2publish-icon-file-add:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e605"}.icon-file-settings:before,.in2publish-icon-file-changed:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e606"}.icon-align-justify:before,.in2publish-icon-file:before{content:"\e607"}.icon-clock2:before{content:"\e60b"}.icon-edit:before,.in2publish-icon-edit:before{content:"\e602"}.nav-pills-container{background:white;padding:10px}div.typo3-fullDoc{height:auto}.in2publish-hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.in2publish-clearfix{zoom:1}.in2publish-clearfix:after{clear:both}.in2publish-clearfix:before,.in2publish-clearfix:after{content:"";display:table}.in2publish-icon-small:before,.in2publish-icon-history:before,.in2publish-icon-info:before,.in2publish-icon-eye:before,.in2publish-icon-edit:before,.in2publish-link-publish .in2publish-icon-publish:before{font-size:16px}.in2publish-unstyledlist{margin:0;padding:0;list-style-type:none}[data-action]{cursor:pointer}.in2publish-inline-block{display:inline-block}.in2publish-backend{font-size:15px;color:#fff}.in2publish-backend h1,.in2publish-backend h2,.in2publish-backend h3,.in2publish-backend h4,.in2publish-backend legend{color:#fff}.in2publish-backend select{color:#444}#typo3-docheader .in2publish-backend-select.module-docheader-bar{overflow:initial}.in2publish-backend *,.in2publish-backend *:before,.in2publish-backend *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.in2publish-backend ul{margin:0;padding:0}.in2publish-module>section{margin:15px 0}.in2publish-module>section>h3{margin-bottom:10px}.in2publish-module{background:#585858}legend{display:block;width:100%;padding:0;margin-bottom:18px;font-size:inherit;line-height:inherit;color:currentColor;border-style:none}label{font-weight:normal}a.in2publish-notextdecoration{text-decoration:none}.in2publish-main{margin-top:40px;overflow:hidden}.in2publish-container{overflow:hidden;margin:0 0 30px}.in2publish-container-50{position:relative;width:50%;float:left;text-align:center}.in2publish-container-50 img{width:90px;height:auto}.in2publish-stagelisting__item__column{background-color:#666;width:50%;float:left;height:30px;line-height:30px;position:relative;top:0;left:0}.in2publish-stagelisting__item__column a{color:#fff}.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column{background-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column{background-color:#A94442}.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column{background-color:#000}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column{background-color:#FFCA4B;color:#585858}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-publish,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-publish{color:#585858}.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column{background-color:#425ea1}.in2publish-list-level--1 .in2publish-icon-info{right:37px}.in2publish-list-level--1 .in2publish-link-publish{right:12px}.in2publish-list-level--1 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:27px}.in2publish-list-level--2 .in2publish-icon-info{right:49px}.in2publish-list-level--2 .in2publish-link-publish{right:24px}.in2publish-list-level--2 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:39px}.in2publish-list-level--3 .in2publish-icon-info{right:61px}.in2publish-list-level--3 .in2publish-link-publish{right:36px}.in2publish-list-level--3 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:51px}.in2publish-list-level--4 .in2publish-icon-info{right:73px}.in2publish-list-level--4 .in2publish-link-publish{right:48px}.in2publish-list-level--4 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:63px}.in2publish-list-level--5 .in2publish-icon-info{right:85px}.in2publish-list-level--5 .in2publish-link-publish{right:60px}.in2publish-list-level--5 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:75px}.in2publish-backend .in2publish-list-level{margin:0 0 0 25px}.in2publish-backend .in2publish-list-level>li{border-top:1px solid #585858}.in2publish-stagelisting__dropdown{display:none;overflow:hidden;background-color:#DBDBDB;color:#585858;border:10px solid #666}.in2publish-stagelisting__dropdown a{color:currentColor}.in2publish-stagelisting__dropdown h3{background-color:#585858;font-weight:normal;font-size:1em;padding:0 15px;margin-top:0}.in2publish-stagelisting__dropdown h4{background-color:#666;font-style:italic;padding:3px 15px}.in2publish-stagelisting__dropdown li{list-style-type:none;padding:0 0 0 15px;word-break:break-all}.in2publish-stagelisting__dropdown [class^="in2publish-icon-"],.in2publish-stagelisting__dropdown [class*=" in2publish-icon-"]{padding:0 10px 0 0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown{border-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown{border-color:#A94442}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown{border-color:#FFCA4B}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown{border-color:#425ea1}.in2publish-stagelisting__dropdown--open{margin-bottom:10px}.in2publish-stagelisting__dropdown__item{width:50%;float:left;line-height:30px;padding:0}.in2publish-stagelisting__dropdown__item--full{width:100%}.in2publish-stagelisting__dropdown__item h3{line-height:30px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list>li{border-style:none;position:relative}.in2publish-stagelisting__dropdown__actions{padding:0 15px;background-color:#A0A0A0;color:#fff}.in2publish-stagelisting__dropdown__actions>a{margin-right:20px}.in2publish-stagelisting__dropdown__actions>a:last-child{margin-right:0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown__actions{background-color:#5D9A46}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown__actions{background-color:#C15955}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown__actions{background-color:#FFDB88;color:currentColor}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown__actions{background-color:#557AD1;color:#fff}.in2publish-stagelisting__dropdown__page{background-color:#fff}.in2publish-backend .in2publish-related__title{font-style:normal;line-height:30px;padding:0 15px;margin:0;background-color:#FFDB88;color:#444}.in2publish-backend .in2publish-related__list{margin:12px 0 15px}.in2publish-backend .in2publish-related__list li{font-size:14px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list{margin-bottom:12px}.in2publish-footer{margin:20px 0;color:#A0A0A0;font-size:80%}.in2publish-footer .in2publish-logo{float:right;width:160px;height:48px}.in2publish-functions-bar{background-color:#666;margin:20px 0;text-align:center;position:relative;padding:15px;min-height:73px}.in2publish-functions-bar__filter{position:absolute;right:20px;top:22px}.in2publish-functions-bar__filter i:before{font-size:30px}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link{display:inline-block;margin:0 0 0 10px;color:#fff}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link:hover{text-decoration:none}.in2publish-functions-bar__filter .in2publish-functions-bar--active{border-bottom:2px solid #fff}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-changed{border-color:#FFCA4B}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-added{border-color:#5D9A46}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-deleted{border-color:#A94442}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-moved{border-color:#557AD1}.in2publish-preloader{background-color:#585858;height:100%;position:fixed;z-index:100000;text-align:center;opacity:0.9;top:0;left:0;right:0;bottom:0}.in2publish-preloader--hidden{display:none}.in2publish-preloader--spinner{position:relative;top:30%;margin:100px auto;width:50px;height:30px;text-align:center;font-size:10px}.in2publish-preloader--spinner>div{background-color:#fff;height:100%;width:6px;display:inline-block;-webkit-animation:stretchdelay 1.2s infinite ease-in-out;animation:stretchdelay 1.2s infinite ease-in-out}.in2publish-preloader--spinner .rect2{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.in2publish-preloader--spinner .rect3{-webkit-animation-delay:-1.0s;animation-delay:-1.0s}.in2publish-preloader--spinner .rect4{-webkit-animation-delay:-0.9s;animation-delay:-0.9s}.in2publish-preloader--spinner .rect5{-webkit-animation-delay:-0.8s;animation-delay:-0.8s}div#typo3-docbody.stopScrolling{transform:none}@-webkit-keyframes stretchdelay{0%, 40%, 100%{-webkit-transform:scaleY(0.4)}20%{-webkit-transform:scaleY(1)}}@keyframes stretchdelay{0%, 40%, 100%{transform:scaleY(0.4);-webkit-transform:scaleY(0.4)}20%{transform:scaleY(1);-webkit-transform:scaleY(1)}}.in2publish-removevalue:before{right:4px;bottom:4px} +.in2publish-icon-info{position:absolute;top:1px;right:25px}.in2publish-icon-loop-alt4:before{font-size:90px !important;color:#5D9A46;position:absolute;top:25px;left:-45px}.in2publish-icon-loop-alt4.in2publish-warning:before{color:#FFCA4B}.in2publish-icon-loop-alt4.in2publish-connection-error:before{color:#A94442}.in2publish-icon-folder{margin:0 15px !important;position:relative;top:3px}.in2publish-icon-file{margin:0 15px;position:relative;top:3px}.in2publish-link-publish{position:absolute;right:0;top:1px}.in2publish-link-publish:hover{text-decoration:none}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish{right:1px;cursor:not-allowed}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish:before{content:"\e60a"}.in2publish-stagelisting__item--removed .in2publish-link-publish .in2publish-icon-publish:hover{color:#5D9A46}@font-face{font-family:'in2publish';src:url("../Fonts/in2publish.eot?abcdef");src:url("../Fonts/in2publish.eot?#iefixabcdef") format("embedded-opentype"),url("../Fonts/in2publish.woff?abcdef") format("woff"),url("../Fonts/in2publish.ttf?abcdef") format("truetype"),url("../Fonts/in2publish.svg?abcdef#in2publish") format("svg");font-weight:normal;font-style:normal}[class^="in2publish-icon-"]:before,[class*=" in2publish-icon-"]:before,.in2publish-messages--removeable>.typo3-message:before{font-family:'in2publish';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;font-size:20px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-circle-o:before,.in2publish-icon-circle-o:before{content:"\f10c"}.icon-circle:before,.in2publish-icon-circle:before{content:"\f111"}.icon-blocked:before,.in2publish-icon-blocked:before{content:"\e60a"}.icon-x-altx-alt:before,.in2publish-icon-x-altx-alt:before{content:"\e609"}.icon-folder-download:before,.in2publish-icon-folder-download:before,.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e608"}.icon-history:before,.in2publish-icon-history:before{content:"\e603"}.icon-info:before,.in2publish-icon-info:before{content:"\e601"}.icon-loop-alt4:before,.in2publish-icon-loop-alt4:before{content:"\e600"}.icon-folder:before,.in2publish-icon-folder:before{content:"\e92f"}.icon-folder-open:before,.in2publish-icon-folder-open:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e930"}.icon-folder-plus:before,.in2publish-icon-folder-plus:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e931"}.icon-folder-minus:before,.in2publish-icon-folder-minus:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e932"}.icon-eye:before,.in2publish-icon-eye:before{content:"\e9ce"}.icon-arrow-right:before,.in2publish-link-publish .in2publish-icon-publish:before{content:"\ea34"}.icon-file-broken:before,.in2publish-icon-file-delete:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e604"}.icon-file-add:before,.in2publish-icon-file-add:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e605"}.icon-file-settings:before,.in2publish-icon-file-changed:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e606"}.icon-align-justify:before,.in2publish-icon-file:before{content:"\e607"}.icon-clock2:before{content:"\e60b"}.icon-edit:before,.in2publish-icon-edit:before{content:"\e602"}.nav-pills-container{background:white;padding:10px}div.typo3-fullDoc{height:auto}.in2publish-hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.in2publish-clearfix{zoom:1}.in2publish-clearfix:after{clear:both}.in2publish-clearfix:before,.in2publish-clearfix:after{content:"";display:table}.in2publish-icon-small:before,.in2publish-icon-history:before,.in2publish-icon-info:before,.in2publish-icon-eye:before,.in2publish-icon-edit:before,.in2publish-link-publish .in2publish-icon-publish:before{font-size:16px}.in2publish-unstyledlist{margin:0;padding:0;list-style-type:none}[data-action]{cursor:pointer}.in2publish-inline-block{display:inline-block}.in2publish-backend{font-size:15px;color:#fff}.in2publish-backend h1,.in2publish-backend h2,.in2publish-backend h3,.in2publish-backend h4,.in2publish-backend legend{color:#fff}.in2publish-backend select{color:#444}#typo3-docheader .in2publish-backend-select.module-docheader-bar{overflow:initial}.in2publish-backend *,.in2publish-backend *:before,.in2publish-backend *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.in2publish-backend ul{margin:0;padding:0}.in2publish-module>section{margin:15px 0}.in2publish-module>section>h3{margin-bottom:10px}.in2publish-module{background:#585858}legend{display:block;width:100%;padding:0;margin-bottom:18px;font-size:inherit;line-height:inherit;color:currentColor;border-style:none}label{font-weight:normal}a.in2publish-notextdecoration{text-decoration:none}.in2publish-main{margin-top:40px;overflow:hidden}.in2publish-container{overflow:hidden;margin:0 0 30px}.in2publish-container-50{position:relative;width:50%;float:left;text-align:center}.in2publish-container-50 img{width:90px;height:auto}.in2publish-stagelisting__item__column{background-color:#666;width:50%;float:left;height:30px;line-height:30px;position:relative;top:0;left:0}.in2publish-stagelisting__item__column a{color:#fff}.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column{background-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column{background-color:#A94442}.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column{background-color:#000}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column{background-color:#FFCA4B;color:#585858}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column a,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column a{color:#585858}.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column{background-color:#425ea1}.in2publish-list-level--1 .in2publish-icon-info{right:37px}.in2publish-list-level--1 .in2publish-link-publish{right:12px}.in2publish-list-level--1 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:27px}.in2publish-list-level--2 .in2publish-icon-info{right:49px}.in2publish-list-level--2 .in2publish-link-publish{right:24px}.in2publish-list-level--2 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:39px}.in2publish-list-level--3 .in2publish-icon-info{right:61px}.in2publish-list-level--3 .in2publish-link-publish{right:36px}.in2publish-list-level--3 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:51px}.in2publish-list-level--4 .in2publish-icon-info{right:73px}.in2publish-list-level--4 .in2publish-link-publish{right:48px}.in2publish-list-level--4 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:63px}.in2publish-list-level--5 .in2publish-icon-info{right:85px}.in2publish-list-level--5 .in2publish-link-publish{right:60px}.in2publish-list-level--5 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:75px}.in2publish-backend .in2publish-list-level{margin:0 0 0 25px}.in2publish-backend .in2publish-list-level>li{border-top:1px solid #585858}.in2publish-stagelisting__dropdown{display:none;overflow:hidden;background-color:#DBDBDB;color:#585858;border:10px solid #666}.in2publish-stagelisting__dropdown a{color:currentColor}.in2publish-stagelisting__dropdown h3{background-color:#585858;font-weight:normal;font-size:1em;padding:0 15px;margin-top:0}.in2publish-stagelisting__dropdown h4{background-color:#666;font-style:italic;padding:3px 15px}.in2publish-stagelisting__dropdown li{list-style-type:none;padding:0 0 0 15px;word-break:break-all}.in2publish-stagelisting__dropdown [class^="in2publish-icon-"],.in2publish-stagelisting__dropdown [class*=" in2publish-icon-"]{padding:0 10px 0 0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown{border-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown{border-color:#A94442}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown{border-color:#FFCA4B}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown{border-color:#425ea1}.in2publish-stagelisting__dropdown--open{margin-bottom:10px}.in2publish-stagelisting__dropdown__item{width:50%;float:left;line-height:30px;padding:0}.in2publish-stagelisting__dropdown__item--full{width:100%}.in2publish-stagelisting__dropdown__item h3{line-height:30px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list>li{border-style:none;position:relative}.in2publish-stagelisting__dropdown__actions{padding:0 15px;background-color:#A0A0A0;color:#fff}.in2publish-stagelisting__dropdown__actions>a{margin-right:20px}.in2publish-stagelisting__dropdown__actions>a:last-child{margin-right:0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown__actions{background-color:#5D9A46}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown__actions{background-color:#C15955}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown__actions{background-color:#FFDB88;color:currentColor}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown__actions{background-color:#557AD1;color:#fff}.in2publish-stagelisting__dropdown__page{background-color:#fff}.in2publish-backend .in2publish-related__title{font-style:normal;line-height:30px;padding:0 15px;margin:0;background-color:#FFDB88;color:#444}.in2publish-backend .in2publish-related__list{margin:12px 0 15px}.in2publish-backend .in2publish-related__list li{font-size:14px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list{margin-bottom:12px}.in2publish-footer{margin:20px 0;color:#A0A0A0;font-size:80%}.in2publish-footer .in2publish-logo{float:right;width:160px;height:48px}.in2publish-functions-bar{background-color:#666;margin:20px 0;text-align:center;position:relative;padding:15px;min-height:73px}.in2publish-functions-bar__filter{position:absolute;right:20px;top:22px}.in2publish-functions-bar__filter i:before{font-size:30px}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link{display:inline-block;margin:0 0 0 10px;color:#fff}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link:hover{text-decoration:none}.in2publish-functions-bar__filter .in2publish-functions-bar--active{border-bottom:2px solid #fff}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-changed{border-color:#FFCA4B}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-added{border-color:#5D9A46}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-deleted{border-color:#A94442}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-moved{border-color:#557AD1}.in2publish-preloader{background-color:#585858;height:100%;position:fixed;z-index:100000;text-align:center;opacity:0.9;top:0;left:0;right:0;bottom:0}.in2publish-preloader--hidden{display:none}.in2publish-preloader--spinner{position:relative;top:30%;margin:100px auto;width:50px;height:30px;text-align:center;font-size:10px}.in2publish-preloader--spinner>div{background-color:#fff;height:100%;width:6px;display:inline-block;-webkit-animation:stretchdelay 1.2s infinite ease-in-out;animation:stretchdelay 1.2s infinite ease-in-out}.in2publish-preloader--spinner .rect2{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.in2publish-preloader--spinner .rect3{-webkit-animation-delay:-1.0s;animation-delay:-1.0s}.in2publish-preloader--spinner .rect4{-webkit-animation-delay:-0.9s;animation-delay:-0.9s}.in2publish-preloader--spinner .rect5{-webkit-animation-delay:-0.8s;animation-delay:-0.8s}div#typo3-docbody.stopScrolling{transform:none}@-webkit-keyframes stretchdelay{0%, 40%, 100%{-webkit-transform:scaleY(0.4)}20%{-webkit-transform:scaleY(1)}}@keyframes stretchdelay{0%, 40%, 100%{transform:scaleY(0.4);-webkit-transform:scaleY(0.4)}20%{transform:scaleY(1);-webkit-transform:scaleY(1)}}.in2publish-removevalue:before{right:4px;bottom:4px} From ffd1112d01e82f8e575362f74045a2c13a667cf2 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Mon, 2 May 2022 15:47:15 +0200 Subject: [PATCH 40/56] [BUGFIX] Write all records recursively to the running requests table Resolves: https://projekte.in2code.de/issues/50387 --- Classes/Domain/Model/RunningRequest.php | 81 ------------------- .../Repository/RunningRequestRepository.php | 40 ++++----- .../Publishing/RunningRequestService.php | 15 ++-- 3 files changed, 29 insertions(+), 107 deletions(-) delete mode 100644 Classes/Domain/Model/RunningRequest.php diff --git a/Classes/Domain/Model/RunningRequest.php b/Classes/Domain/Model/RunningRequest.php deleted file mode 100644 index 21db81097..000000000 --- a/Classes/Domain/Model/RunningRequest.php +++ /dev/null @@ -1,81 +0,0 @@ -recordId = $recordId; - $this->tableName = $tableName; - $this->requestToken = $requestToken; - $this->timestampBegin = ($timestampBegin > 0 ? $timestampBegin : time()); - } - - public function getRecordId(): int - { - return $this->recordId; - } - - public function setRecordId(int $recordId) - { - $this->recordId = $recordId; - - } - - public function getTableName(): string - { - return $this->tableName; - } - - public function setTableName(string $tableName) - { - $this->tableName = $tableName; - - } - - public function getRequestToken(): string - { - return $this->requestToken; - } - - public function setRequestToken(string $requestToken) - { - $this->requestToken = $requestToken; - - } - - public function getTimestampBegin(): int - { - return $this->timestampBegin; - } - - public function setTimestampBegin(int $timestampBegin) - { - $this->timestampBegin = $timestampBegin; - } - -} diff --git a/Classes/Domain/Repository/RunningRequestRepository.php b/Classes/Domain/Repository/RunningRequestRepository.php index fcb41ea84..19e6790ad 100644 --- a/Classes/Domain/Repository/RunningRequestRepository.php +++ b/Classes/Domain/Repository/RunningRequestRepository.php @@ -15,6 +15,8 @@ class RunningRequestRepository /** @var Connection */ protected $connection; + protected $inserts = []; + protected $rtc = []; public function __construct() @@ -22,12 +24,22 @@ public function __construct() $this->connection = DatabaseUtility::buildLocalDatabaseConnection(); } - public function add(RunningRequest $runningRequest): void + public function add($recordId, $tableName, $token): void + { + $uniqueKey = $tableName . '/' . $recordId; + $this->inserts[$uniqueKey] = [ + 'uid' => null, + 'record_id' => $recordId, + 'table_name' => $tableName, + 'request_token' => $token, + 'timestamp_begin' => $GLOBALS['EXEC_TIME'], + ]; + } + + public function flush(): void { - $this->connection->insert( - self::RUNNING_REQUEST_TABLE_NAME, - $this->mapProperties($runningRequest) - ); + $this->connection->bulkInsert(self::RUNNING_REQUEST_TABLE_NAME, $this->inserts); + $this->inserts = []; } /** @@ -38,8 +50,8 @@ public function isPublishingInDifferentRequest($identifier, string $tableName, s if (!isset($this->rtc['content'])) { $query = $this->connection->createQueryBuilder(); $query->select('*') - ->from(self::RUNNING_REQUEST_TABLE_NAME) - ->where($query->expr()->neq('request_token', $query->createNamedParameter($token))); + ->from(self::RUNNING_REQUEST_TABLE_NAME) + ->where($query->expr()->neq('request_token', $query->createNamedParameter($token))); $result = $query->execute(); foreach ($result->fetchAll() as $row) { $this->rtc['content'][$row['table_name']][$row['record_id']] = true; @@ -52,17 +64,7 @@ public function deleteAllByToken(string $token): void { $query = $this->connection->createQueryBuilder(); $query->delete(self::RUNNING_REQUEST_TABLE_NAME) - ->where($query->expr()->eq('request_token', $query->createNamedParameter($token))) - ->execute(); - } - - protected function mapProperties(RunningRequest $runningRequest): array - { - return [ - 'record_id' => $runningRequest->getRecordId(), - 'table_name' => $runningRequest->getTableName(), - 'request_token' => $runningRequest->getRequestToken(), - 'timestamp_begin' => $runningRequest->getTimestampBegin(), - ]; + ->where($query->expr()->eq('request_token', $query->createNamedParameter($token))) + ->execute(); } } diff --git a/Classes/Domain/Service/Publishing/RunningRequestService.php b/Classes/Domain/Service/Publishing/RunningRequestService.php index 41b31b10f..c84c14cf7 100644 --- a/Classes/Domain/Service/Publishing/RunningRequestService.php +++ b/Classes/Domain/Service/Publishing/RunningRequestService.php @@ -47,11 +47,7 @@ public function onRecordPublishingBegan(RecursiveRecordPublishingBegan $event): $record = $event->getRecord(); $this->writeToRunningRequestsTable($record); - foreach ($record->getRelatedRecords() as $relatedRecords) { - foreach ($relatedRecords as $relatedRecord) { - $this->writeToRunningRequestsTable($relatedRecord); - } - } + $this->runningRequestRepository->flush(); } protected function writeToRunningRequestsTable(RecordInterface $record): void @@ -59,8 +55,13 @@ protected function writeToRunningRequestsTable(RecordInterface $record): void $recordId = $record->getIdentifier(); $tableName = $record->getTableName(); - $runningRequest = new RunningRequest($recordId, $tableName, $this->requestToken); - $this->runningRequestRepository->add($runningRequest); + $this->runningRequestRepository->add($recordId, $tableName, $this->requestToken); + + foreach ($record->getRelatedRecords() as $relatedRecords) { + foreach ($relatedRecords as $relatedRecord) { + $this->writeToRunningRequestsTable($relatedRecord); + } + } } public function isPublishable(VoteIfRecordIsPublishable $event): void From 43f0014764da7c70331181d2ae136e9d33d10d59 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Mon, 2 May 2022 16:52:19 +0200 Subject: [PATCH 41/56] [BUGFIX] Mark all records as being published when bulk-publishing Resolves: https://projekte.in2code.de/issues/50387 --- .../Publishing/RunningRequestService.php | 34 ++++++++--- .../RecordsWereSelectedForPublishing.php | 56 +++++++++++++++++++ .../Controller/RedirectController.php | 10 +++- Configuration/Services.yaml | 6 +- 4 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 Classes/Event/RecordsWereSelectedForPublishing.php diff --git a/Classes/Domain/Service/Publishing/RunningRequestService.php b/Classes/Domain/Service/Publishing/RunningRequestService.php index c84c14cf7..219886634 100644 --- a/Classes/Domain/Service/Publishing/RunningRequestService.php +++ b/Classes/Domain/Service/Publishing/RunningRequestService.php @@ -9,6 +9,7 @@ use In2code\In2publishCore\Domain\Model\RunningRequest; use In2code\In2publishCore\Domain\Repository\RunningRequestRepository; use In2code\In2publishCore\Event\DetermineIfRecordIsPublishing; +use In2code\In2publishCore\Event\RecordsWereSelectedForPublishing; use In2code\In2publishCore\Event\RecursiveRecordPublishingBegan; use In2code\In2publishCore\Event\VoteIfRecordIsPublishable; use TYPO3\CMS\Core\SingletonInterface; @@ -32,16 +33,9 @@ public function __construct(RunningRequestRepository $runningRequestRepository) $this->requestToken = bin2hex(random_bytes(16)); } - public function onRecordPublishingBegan(RecursiveRecordPublishingBegan $event): void + public function onRecursiveRecordPublishingBegan(RecursiveRecordPublishingBegan $event): void { - if (!$this->shutdownFunctionRegistered) { - $repository = $this->runningRequestRepository; - $token = $this->requestToken; - register_shutdown_function(static function () use ($repository, $token) { - $repository->deleteAllByToken($token); - }); - $this->shutdownFunctionRegistered = true; - } + $this->registerShutdownFunction(); /** @var Record $record */ $record = $event->getRecord(); @@ -50,6 +44,16 @@ public function onRecordPublishingBegan(RecursiveRecordPublishingBegan $event): $this->runningRequestRepository->flush(); } + public function onRecordsWereSelectedForPublishing(RecordsWereSelectedForPublishing $event): void + { + $this->registerShutdownFunction(); + + foreach ($event->getRecords() as $record) { + $this->writeToRunningRequestsTable($record); + } + $this->runningRequestRepository->flush(); + } + protected function writeToRunningRequestsTable(RecordInterface $record): void { $recordId = $record->getIdentifier(); @@ -81,4 +85,16 @@ public function isPublishing(DetermineIfRecordIsPublishing $event): void $event->setIsPublishing(); } } + + protected function registerShutdownFunction(): void + { + if (!$this->shutdownFunctionRegistered) { + $repository = $this->runningRequestRepository; + $token = $this->requestToken; + register_shutdown_function(static function () use ($repository, $token) { + $repository->deleteAllByToken($token); + }); + $this->shutdownFunctionRegistered = true; + } + } } diff --git a/Classes/Event/RecordsWereSelectedForPublishing.php b/Classes/Event/RecordsWereSelectedForPublishing.php new file mode 100644 index 000000000..101860a90 --- /dev/null +++ b/Classes/Event/RecordsWereSelectedForPublishing.php @@ -0,0 +1,56 @@ + + * + * 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! + */ + +use In2code\In2publishCore\Domain\Model\Record; + +final class RecordsWereSelectedForPublishing +{ + /** + * @var array + */ + private $records; + + /** + * @param array $records + */ + public function __construct(array $records) + { + $this->records = $records; + } + + /** + * @return array + */ + public function getRecords(): array + { + return $this->records; + } +} diff --git a/Classes/Features/RedirectsSupport/Controller/RedirectController.php b/Classes/Features/RedirectsSupport/Controller/RedirectController.php index 464b66a8d..ed473f0b6 100644 --- a/Classes/Features/RedirectsSupport/Controller/RedirectController.php +++ b/Classes/Features/RedirectsSupport/Controller/RedirectController.php @@ -36,6 +36,7 @@ use In2code\In2publishCore\Controller\AbstractController; use In2code\In2publishCore\Domain\Service\ExecutionTimeService; use In2code\In2publishCore\Domain\Service\ForeignSiteFinder; +use In2code\In2publishCore\Event\RecordsWereSelectedForPublishing; use In2code\In2publishCore\Features\RedirectsSupport\Domain\Dto\Filter; use In2code\In2publishCore\Features\RedirectsSupport\Domain\Repository\SysRedirectRepository; use In2code\In2publishCore\Service\Environment\EnvironmentService; @@ -142,13 +143,20 @@ public function publishAction(array $redirects): void } unset($redirect); + $records = []; foreach ($redirects as $redirect) { $record = $this->recordFinder->findRecordByUidForPublishing($redirect, 'sys_redirect'); if (null !== $record) { - $this->recordPublisher->publishRecordRecursive($record); + $records[] = $record; } } + $this->eventDispatcher->dispatch(new RecordsWereSelectedForPublishing($records)); + + foreach ($records as $record) { + $this->recordPublisher->publishRecordRecursive($record); + } + $this->runTasks(); if (count($redirects) === 1) { $this->addFlashMessage(sprintf('Redirect %s published', reset($redirects))); diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 8c6fc996c..7ef0a6f04 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -104,8 +104,12 @@ services: tags: - name: event.listener identifier: 'in2publishcore-RunningRequestService-RecursiveRecordPublishingBegan' - method: 'onRecordPublishingBegan' + method: 'onRecursiveRecordPublishingBegan' event: In2code\In2publishCore\Event\RecursiveRecordPublishingBegan + - name: event.listener + identifier: 'in2publishcore-RunningRequestService-RecordsWereSelectedForPublishing' + method: 'onRecordsWereSelectedForPublishing' + event: In2code\In2publishCore\Event\RecordsWereSelectedForPublishing - name: event.listener identifier: 'in2publishcore-RunningRequestService-VoteIfRecordIsPublishable' method: 'isPublishable' From cf3b3245742218c6c0a8d032cf4854ce294f81cc Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Mon, 2 May 2022 17:02:49 +0200 Subject: [PATCH 42/56] [COMMENT] Add copyright blocks to new RunningRequest classes Related: https://projekte.in2code.de/issues/50387 --- .../Repository/RunningRequestRepository.php | 27 ++++++++++++- .../Publishing/RunningRequestService.php | 27 ++++++++++++- .../Event/DetermineIfRecordIsPublishing.php | 25 ++++++++++++ .../RecordsWereSelectedForPublishing.php | 2 +- .../Database/TableGarbageCollectorTest.php | 40 +++++++++++++++---- Classes/ViewHelpers/RegisterViewHelper.php | 25 ++++++++++++ 6 files changed, 136 insertions(+), 10 deletions(-) diff --git a/Classes/Domain/Repository/RunningRequestRepository.php b/Classes/Domain/Repository/RunningRequestRepository.php index 19e6790ad..46774bfb5 100644 --- a/Classes/Domain/Repository/RunningRequestRepository.php +++ b/Classes/Domain/Repository/RunningRequestRepository.php @@ -4,7 +4,32 @@ namespace In2code\In2publishCore\Domain\Repository; -use In2code\In2publishCore\Domain\Model\RunningRequest; +/* + * Copyright notice + * + * (c) 2022 in2code.de and the following authors: + * Christine Zoglmeier + * Oliver Eglseder + * + * 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! + */ + use In2code\In2publishCore\Utility\DatabaseUtility; use TYPO3\CMS\Core\Database\Connection; diff --git a/Classes/Domain/Service/Publishing/RunningRequestService.php b/Classes/Domain/Service/Publishing/RunningRequestService.php index 219886634..d37136741 100644 --- a/Classes/Domain/Service/Publishing/RunningRequestService.php +++ b/Classes/Domain/Service/Publishing/RunningRequestService.php @@ -4,9 +4,34 @@ namespace In2code\In2publishCore\Domain\Service\Publishing; +/* + * Copyright notice + * + * (c) 2022 in2code.de and the following authors: + * Christine Zoglmeier + * Oliver Eglseder + * + * 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! + */ + use In2code\In2publishCore\Domain\Model\Record; use In2code\In2publishCore\Domain\Model\RecordInterface; -use In2code\In2publishCore\Domain\Model\RunningRequest; use In2code\In2publishCore\Domain\Repository\RunningRequestRepository; use In2code\In2publishCore\Event\DetermineIfRecordIsPublishing; use In2code\In2publishCore\Event\RecordsWereSelectedForPublishing; diff --git a/Classes/Event/DetermineIfRecordIsPublishing.php b/Classes/Event/DetermineIfRecordIsPublishing.php index d5d70e2e5..eccb8f55a 100644 --- a/Classes/Event/DetermineIfRecordIsPublishing.php +++ b/Classes/Event/DetermineIfRecordIsPublishing.php @@ -4,6 +4,31 @@ namespace In2code\In2publishCore\Event; +/* + * Copyright notice + * + * (c) 2022 in2code.de and the following authors: + * Oliver Eglseder + * + * 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! + */ + use Psr\EventDispatcher\StoppableEventInterface; final class DetermineIfRecordIsPublishing implements StoppableEventInterface diff --git a/Classes/Event/RecordsWereSelectedForPublishing.php b/Classes/Event/RecordsWereSelectedForPublishing.php index 101860a90..0ada82fe8 100644 --- a/Classes/Event/RecordsWereSelectedForPublishing.php +++ b/Classes/Event/RecordsWereSelectedForPublishing.php @@ -7,7 +7,7 @@ /* * Copyright notice * - * (c) 2021 in2code.de and the following authors: + * (c) 2022 in2code.de and the following authors: * Oliver Eglseder * * All rights reserved diff --git a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php index 6a71965a1..ffbcce513 100644 --- a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php +++ b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php @@ -4,6 +4,32 @@ namespace In2code\In2publishCore\Testing\Tests\Database; +/* + * Copyright notice + * + * (c) 2022 in2code.de and the following authors: + * Christine Zoglmeier + * Oliver Eglseder + * + * 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! + */ + use In2code\In2publishCore\Testing\Tests\TestCaseInterface; use In2code\In2publishCore\Testing\Tests\TestResult; use In2code\In2publishCore\Utility\DatabaseUtility; @@ -25,13 +51,13 @@ public function run(): TestResult $query = $localDatabase->createQueryBuilder(); $query->count('*') - ->from('tx_scheduler_task') - ->where( - $query->expr()->like( - 'serialized_task_object', - $query->createNamedParameter('%tx_in2publishcore_running_request%') - ) - ); + ->from('tx_scheduler_task') + ->where( + $query->expr()->like( + 'serialized_task_object', + $query->createNamedParameter('%tx_in2publishcore_running_request%') + ) + ); $statement = $query->execute(); if (0 === $statement->fetchColumn()) { diff --git a/Classes/ViewHelpers/RegisterViewHelper.php b/Classes/ViewHelpers/RegisterViewHelper.php index e47072355..5b35bdf0c 100644 --- a/Classes/ViewHelpers/RegisterViewHelper.php +++ b/Classes/ViewHelpers/RegisterViewHelper.php @@ -4,6 +4,31 @@ namespace In2code\In2publishCore\ViewHelpers; +/* + * Copyright notice + * + * (c) 2022 in2code.de and the following authors: + * Oliver Eglseder + * + * 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! + */ + use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper; /** From 6a85c800ddc6acfc315247ce1830c5a0b00ebc05 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Mon, 2 May 2022 13:46:01 +0200 Subject: [PATCH 43/56] [BUGFIX] Hide publish file/redirect button if the record is being published Resolves: https://projekte.in2code.de/issues/50387 --- .../Private/Partials/File/Index/FileList.html | 35 ++++++++++++------- .../Private/Templates/Redirect/List.html | 2 +- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Resources/Private/Partials/File/Index/FileList.html b/Resources/Private/Partials/File/Index/FileList.html index 1ea7846ae..342829b1c 100755 --- a/Resources/Private/Partials/File/Index/FileList.html +++ b/Resources/Private/Partials/File/Index/FileList.html @@ -89,19 +89,28 @@ - - - - - + + + + + + + + + + + + + + diff --git a/Resources/Private/Templates/Redirect/List.html b/Resources/Private/Templates/Redirect/List.html index 9766dede8..e1ed04b0b 100644 --- a/Resources/Private/Templates/Redirect/List.html +++ b/Resources/Private/Templates/Redirect/List.html @@ -76,7 +76,7 @@ - + From af3b46ed67e6028682eb3ff1df2d488a5b0199ba Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 3 May 2022 13:57:37 +0200 Subject: [PATCH 44/56] [REFACTOR] Replace classes for constant access with the class that defines the constant --- Classes/Domain/Factory/FileIndexFactory.php | 14 ++++----- Classes/Utility/LogUtility.php | 2 +- Tests/Unit/Domain/Model/RecordTest.php | 31 ++++++++++--------- .../Processor/BackendUserProcessorTest.php | 2 +- ext_localconf.php | 4 +-- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/Classes/Domain/Factory/FileIndexFactory.php b/Classes/Domain/Factory/FileIndexFactory.php index 1f77d50d6..e8a9313dd 100644 --- a/Classes/Domain/Factory/FileIndexFactory.php +++ b/Classes/Domain/Factory/FileIndexFactory.php @@ -36,8 +36,8 @@ use In2code\In2publishCore\Service\Database\UidReservationService; use In2code\In2publishCore\Utility\DatabaseUtility; use LogicException; +use TYPO3\CMS\Core\Resource\AbstractFile; use TYPO3\CMS\Core\Resource\Driver\DriverInterface; -use TYPO3\CMS\Core\Resource\File; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\PathUtility; @@ -250,23 +250,23 @@ protected function determineFileType(array $fileInfo): int [$fileType] = explode('/', $fileInfo['mime_type']); switch (strtolower($fileType)) { case 'text': - $type = File::FILETYPE_TEXT; + $type = AbstractFile::FILETYPE_TEXT; break; case 'image': - $type = File::FILETYPE_IMAGE; + $type = AbstractFile::FILETYPE_IMAGE; break; case 'audio': - $type = File::FILETYPE_AUDIO; + $type = AbstractFile::FILETYPE_AUDIO; break; case 'video': - $type = File::FILETYPE_VIDEO; + $type = AbstractFile::FILETYPE_VIDEO; break; case 'application': case 'software': - $type = File::FILETYPE_APPLICATION; + $type = AbstractFile::FILETYPE_APPLICATION; break; default: - $type = File::FILETYPE_UNKNOWN; + $type = AbstractFile::FILETYPE_UNKNOWN; } return $type; } diff --git a/Classes/Utility/LogUtility.php b/Classes/Utility/LogUtility.php index c4eff9c6f..5e1f0afa3 100644 --- a/Classes/Utility/LogUtility.php +++ b/Classes/Utility/LogUtility.php @@ -27,7 +27,7 @@ * This copyright notice MUST APPEAR in all copies of the script! */ -use TYPO3\CMS\Core\Log\LogLevel; +use Psr\Log\LogLevel; use TYPO3\CMS\Core\Messaging\AbstractMessage; class LogUtility diff --git a/Tests/Unit/Domain/Model/RecordTest.php b/Tests/Unit/Domain/Model/RecordTest.php index 257a1357f..59656763c 100644 --- a/Tests/Unit/Domain/Model/RecordTest.php +++ b/Tests/Unit/Domain/Model/RecordTest.php @@ -5,6 +5,7 @@ namespace In2code\In2publishCore\Tests\Unit\Domain\Model; use In2code\In2publishCore\Domain\Model\Record; +use In2code\In2publishCore\Domain\Model\RecordInterface; use In2code\In2publishCore\Tests\UnitTestCase; use LogicException; use PHPUnit\Framework\MockObject\MockObject; @@ -147,7 +148,7 @@ public function testStateOfRecordIsAddedIfOnlyLocalPropertiesAreSet() $stub->__construct('tt_content', ['uid' => 1], [], [], []); - $this->assertSame(Record::RECORD_STATE_ADDED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_ADDED, $stub->getState()); } /** @@ -164,7 +165,7 @@ public function testStateOfRecordIsDeletedIfOnlyForeignPropertiesAreSet() $stub = $this->getRecordStub([]); $stub->__construct('tt_content', [], ['uid' => 1], [], []); - $this->assertSame(Record::RECORD_STATE_DELETED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_DELETED, $stub->getState()); } /** @@ -178,22 +179,22 @@ public function testPropertyArraysAreConsideredEmptyIfSpecificFieldsAreNotSet() // no uid or uid_local/uid_foreign. this is not a valid record $stub = $this->getRecordStub([]); $stub->__construct('tt_content', ['foo' => 'bar'], [], [], []); - $this->assertSame(Record::RECORD_STATE_UNCHANGED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_UNCHANGED, $stub->getState()); // uid_local + uid_foreign = valid $stub = $this->getRecordStub([]); $stub->__construct('tt_content', ['uid_local' => 'bar', 'uid_foreign' => 'baz'], [], [], []); - $this->assertSame(Record::RECORD_STATE_ADDED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_ADDED, $stub->getState()); // only uid_local not valid $stub = $this->getRecordStub([]); $stub->__construct('tt_content', ['uid_local' => 'bar'], [], [], []); - $this->assertSame(Record::RECORD_STATE_UNCHANGED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_UNCHANGED, $stub->getState()); // only uid_foreign not valid $stub = $this->getRecordStub([]); $stub->__construct('tt_content', ['uid_foreign' => 'bar'], [], [], []); - $this->assertSame(Record::RECORD_STATE_UNCHANGED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_UNCHANGED, $stub->getState()); } /** @@ -215,7 +216,7 @@ public function testRecordIsMarkedAsDeletedDefinedByDeleteFieldFromTca() ['ctrl' => ['delete' => 'foo']], [] ); - $this->assertSame(Record::RECORD_STATE_DELETED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_DELETED, $stub->getState()); } /** @@ -225,7 +226,7 @@ public function testRecordIsMarkedAsChangedIfItExistsOnBothSidesAndPropertiesDif { $stub = $this->getRecordStub([]); $stub->__construct('tt_content', ['uid' => 1, 'foo' => 'bar'], ['uid' => 1, 'foo' => 'baz'], [], []); - $this->assertSame(Record::RECORD_STATE_CHANGED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_CHANGED, $stub->getState()); } /** @@ -235,7 +236,7 @@ public function testSysFileRecordsAreMovedIfIdentifiersDifferInsteadOfChanged() { $stub = $this->getRecordStub([]); $stub->__construct('sys_file', ['identifier' => 'bar'], ['identifier' => 'baz'], [], []); - $this->assertSame(Record::RECORD_STATE_MOVED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_MOVED, $stub->getState()); } /** @@ -245,7 +246,7 @@ public function testSysFileRecordsAreTreatedAsNormalRecordsIfIdentifierPropertie { $stub = $this->getRecordStub([]); $stub->__construct('sys_file', ['identifier' => 'bar'], ['identifier' => 'bar'], [], []); - $this->assertSame(Record::RECORD_STATE_UNCHANGED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_UNCHANGED, $stub->getState()); } /** @@ -256,7 +257,7 @@ public function testRecordIsValidIfTableNameIsFolderAndNameIsSet() // no uid or uid_local/uid_foreign. this is not a valid record $stub = $this->getRecordStub([]); $stub->__construct('folders', ['name' => 'bar'], ['name' => 'baz'], [], []); - $this->assertSame(Record::RECORD_STATE_CHANGED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_CHANGED, $stub->getState()); } /** @@ -267,7 +268,7 @@ public function testRecordIsInvalidIfTableNameIsFolderAndNameIsNotSet() // no uid or uid_local/uid_foreign. this is not a valid record $stub = $this->getRecordStub([]); $stub->__construct('folders', ['name' => 'bar'], [], [], []); - $this->assertSame(Record::RECORD_STATE_ADDED, $stub->getState()); + $this->assertSame(RecordInterface::RECORD_STATE_ADDED, $stub->getState()); } /** @@ -975,7 +976,7 @@ public function testGetStateRecursiveReturnsRootStateIfRootIsNotUnchanged() $root->addRelatedRecord($sub); - $this->assertSame(Record::RECORD_STATE_CHANGED, $root->getStateRecursive()); + $this->assertSame(RecordInterface::RECORD_STATE_CHANGED, $root->getStateRecursive()); } /** @@ -994,7 +995,7 @@ public function testGetStateRecursiveReturnsRelatedRecordsStateIfRootIsUnchanged $root->addRelatedRecord($sub); - $this->assertSame(Record::RECORD_STATE_CHANGED, $root->getStateRecursive()); + $this->assertSame(RecordInterface::RECORD_STATE_CHANGED, $root->getStateRecursive()); } /** @@ -1056,7 +1057,7 @@ public function testGetStateRecursiveIgnoresRelatedPageRecords() $root->addRelatedRecord($sub); - $this->assertSame(Record::RECORD_STATE_UNCHANGED, $root->getStateRecursive()); + $this->assertSame(RecordInterface::RECORD_STATE_UNCHANGED, $root->getStateRecursive()); } /** diff --git a/Tests/Unit/Log/Processor/BackendUserProcessorTest.php b/Tests/Unit/Log/Processor/BackendUserProcessorTest.php index 27f9689f5..cbf6d8cf4 100644 --- a/Tests/Unit/Log/Processor/BackendUserProcessorTest.php +++ b/Tests/Unit/Log/Processor/BackendUserProcessorTest.php @@ -31,8 +31,8 @@ use In2code\In2publishCore\Log\Processor\BackendUserProcessor; use In2code\In2publishCore\Tests\UnitTestCase; +use Psr\Log\LogLevel; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; -use TYPO3\CMS\Core\Log\LogLevel; use TYPO3\CMS\Core\Log\LogRecord; /** diff --git a/ext_localconf.php b/ext_localconf.php index 44f1d24aa..6501ad040 100755 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -110,7 +110,7 @@ /***************************************** Register Communication Adapter *****************************************/ $adapterRegistry->registerAdapter( - \In2code\In2publishCore\Communication\RemoteCommandExecution\RemoteAdapter\SshAdapter::ADAPTER_TYPE, + \In2code\In2publishCore\Communication\RemoteCommandExecution\RemoteAdapter\AdapterInterface::ADAPTER_TYPE, \In2code\In2publishCore\Communication\RemoteCommandExecution\RemoteAdapter\SshAdapter::ADAPTER_KEY, \In2code\In2publishCore\Communication\RemoteCommandExecution\RemoteAdapter\SshAdapter::class, 'LLL:EXT:in2publish_core/Resources/Private/Language/locallang.xlf:adapter.remote.ssh', @@ -120,7 +120,7 @@ ] ); $adapterRegistry->registerAdapter( - \In2code\In2publishCore\Communication\TemporaryAssetTransmission\TransmissionAdapter\SshAdapter::ADAPTER_TYPE, + \In2code\In2publishCore\Communication\TemporaryAssetTransmission\TransmissionAdapter\AdapterInterface::ADAPTER_TYPE, \In2code\In2publishCore\Communication\TemporaryAssetTransmission\TransmissionAdapter\SshAdapter::ADAPTER_KEY, \In2code\In2publishCore\Communication\TemporaryAssetTransmission\TransmissionAdapter\SshAdapter::class, 'LLL:EXT:in2publish_core/Resources/Private/Language/locallang.xlf:adapter.transmission.ssh', From 2ef0d0bc7508a40950205fa1ca19c5fd85f96500 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 3 May 2022 14:00:56 +0200 Subject: [PATCH 45/56] [CLEANUP] Remove unnecessary string concatenation from BackendUtilityTest --- Tests/Unit/Utility/BackendUtilityTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Unit/Utility/BackendUtilityTest.php b/Tests/Unit/Utility/BackendUtilityTest.php index 72233fd1b..94328cab3 100644 --- a/Tests/Unit/Utility/BackendUtilityTest.php +++ b/Tests/Unit/Utility/BackendUtilityTest.php @@ -115,7 +115,7 @@ public function testGetPageIdentifierReturnsPidForRollbackRequests() $this->rows = ['uid' => $uid, 'pid' => $expectedPid]; - $_POST['element'] = '' . $table . ':' . $uid . ''; + $_POST['element'] = $table . ':' . $uid; $this->assertSame($expectedPid, BackendUtility::getPageIdentifier()); } From 2c9f6ab631c0fe388ae980708b885c0e86673413 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 3 May 2022 15:04:24 +0200 Subject: [PATCH 46/56] [BUGFIX] Replace deprecated FILTER_SANITIZE_STRING option from filter_var with htmlspecialchars --- .../RemoteCommandResponse.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Classes/Communication/RemoteCommandExecution/RemoteCommandResponse.php b/Classes/Communication/RemoteCommandExecution/RemoteCommandResponse.php index ff9ba36a5..300102f60 100644 --- a/Classes/Communication/RemoteCommandExecution/RemoteCommandResponse.php +++ b/Classes/Communication/RemoteCommandExecution/RemoteCommandResponse.php @@ -33,15 +33,12 @@ use function array_values; use function explode; -use function filter_var; +use function htmlspecialchars; use function implode; use function is_array; use function is_string; -use const FILTER_FLAG_NO_ENCODE_QUOTES; -use const FILTER_FLAG_STRIP_HIGH; -use const FILTER_FLAG_STRIP_LOW; -use const FILTER_SANITIZE_STRING; +use const ENT_NOQUOTES; use const PHP_EOL; class RemoteCommandResponse @@ -134,11 +131,7 @@ protected function convertAndSanitizeResponse($response): array } $sanitized = []; foreach ($response as $row => $string) { - $sanitized[$row] = filter_var( - $string, - FILTER_SANITIZE_STRING, - FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH | FILTER_FLAG_NO_ENCODE_QUOTES - ); + $sanitized[$row] = htmlspecialchars($string, ENT_NOQUOTES); } return $sanitized; } From 61d413faab2e279bc670697b44829d848d38d81a Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 3 May 2022 15:26:50 +0200 Subject: [PATCH 47/56] [BUGFIX] Add explanation to the failing TableGarbageCollectorTest result --- .../Database/TableGarbageCollectorTest.php | 3 ++- .../Private/Language/de.locallang.testing.xlf | 25 +++++++++++-------- .../Private/Language/locallang.testing.xlf | 8 +++--- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php index ffbcce513..52121757f 100644 --- a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php +++ b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php @@ -63,7 +63,8 @@ public function run(): TestResult if (0 === $statement->fetchColumn()) { return new TestResult( 'database.garbage_collector_task_missing', - TestResult::ERROR + TestResult::ERROR, + ['database.garbage_collector_task_missing.explanation'] ); } diff --git a/Resources/Private/Language/de.locallang.testing.xlf b/Resources/Private/Language/de.locallang.testing.xlf index d6d171cfe..73acde780 100644 --- a/Resources/Private/Language/de.locallang.testing.xlf +++ b/Resources/Private/Language/de.locallang.testing.xlf @@ -154,6 +154,20 @@ Diese Tabellen haben Unterschiede: + + + A table garbage collector task for table tx_in2publishcore_running_request is missing. + Ein "Tabellen-Müllsammlung" Scheduler Task für die Tabelle "tx_in2publishcore_running_request" muss angelegt werden. + + + Since there is no "Table garbage collection" task for the "tx_in2publishcore_running_request" table, the table may keep growing when unforeseen errors occur. This could block the publishing of some records. + Da kein Task "Tabellen-Müllsammlung" für die Tabelle "tx_in2publishcore_running_request" existiert, kann es sein, dass die Tabelle immer weiter anwächst wenn unvorhergesehen Fehler auftreten. Dadurch könnte das veröffentlichen von Datensätzen blockiert werden. + + + A table garbage collector task for table tx_in2publishcore_running_request exists + Ein Table Garbage Collector Task für die Tabelle tx_in2publishcore_running_request ist vorhanden + + @@ -174,17 +188,6 @@ Die Funktion "ssh2_sftp_chmod" steht ab der Version 0.12 von php_ssh2 zu Verfügung. Upgraden Sie php_ssh2 oder ignorieren Sie diese Meldung. - - - A table garbage collector task for table tx_in2publishcore_running_request is missing - Es muss ein Table Garbage Collector Task für die Tabelle tx_in2publishcore_running_request angelegt werden - - - - A table garbage collector task for table tx_in2publishcore_running_request exists - Ein Table Garbage Collector Task für die Tabelle tx_in2publishcore_running_request ist vorhanden - - diff --git a/Resources/Private/Language/locallang.testing.xlf b/Resources/Private/Language/locallang.testing.xlf index 6335b69b7..3207b518d 100644 --- a/Resources/Private/Language/locallang.testing.xlf +++ b/Resources/Private/Language/locallang.testing.xlf @@ -126,9 +126,11 @@ - A table garbage collector task for table tx_in2publishcore_running_request is missing + A table garbage collector task for table tx_in2publishcore_running_request is missing. + + + Since there is no "Table garbage collection" task for the "tx_in2publishcore_running_request" table, the table may keep growing when unforeseen errors occur. This could block the publishing of some records. - A table garbage collector task for table tx_in2publishcore_running_request exists @@ -147,7 +149,6 @@ The function "ssh2_sftp_chmod" is available since php_ssh2 0.12. Either upgrade or ignore this message. - Die Funktion "ssh2_sftp_chmod" steht ab der Version 0.12 von php_ssh2 zu Verfügung. Upgraden Sie php_ssh2 oder ignorieren Sie diese Meldung. @@ -470,7 +471,6 @@ The Remote Command Dispatcher initialization took %f seconds on average - Die Initialisierung des Remote Command Dispatcher benötigt im Schnitt %f Sekunden From 91050d51ffd78a7275622ffdafb3827b9a17bfc6 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 3 May 2022 15:34:02 +0200 Subject: [PATCH 48/56] [CODESTYLE] Fix all CS issues in the Tests folder --- Build/FunctionalTestsBootstrap.php | 4 +++- Build/UnitTestsBootstrap.php | 6 +++++- Tests/FunctionalTestCase.php | 11 ++++++----- Tests/Unit/Domain/Model/RecordTest.php | 18 +++++++++--------- Tests/Unit/Utility/BackendUtilityTest.php | 2 +- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/Build/FunctionalTestsBootstrap.php b/Build/FunctionalTestsBootstrap.php index 94cd966dc..7b8c25023 100644 --- a/Build/FunctionalTestsBootstrap.php +++ b/Build/FunctionalTestsBootstrap.php @@ -12,11 +12,13 @@ * The TYPO3 project - inspiring people to share! */ +use TYPO3\TestingFramework\Core\Testbase; + call_user_func(function () { if (!getenv('IN2PUBLISH_CONTEXT')) { putenv('IN2PUBLISH_CONTEXT=Local'); } - $testbase = new \TYPO3\TestingFramework\Core\Testbase(); + $testbase = new Testbase(); $testbase->defineOriginalRootPath(); $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/tests'); $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/transient'); diff --git a/Build/UnitTestsBootstrap.php b/Build/UnitTestsBootstrap.php index 9e8d6260b..cd276956c 100644 --- a/Build/UnitTestsBootstrap.php +++ b/Build/UnitTestsBootstrap.php @@ -116,7 +116,11 @@ 'boot.state' => $bootState, ]); - $container = $builder->createDependencyInjectionContainer($packageManager, $dependencyInjectionContainerCache, false); + $container = $builder->createDependencyInjectionContainer( + $packageManager, + $dependencyInjectionContainerCache, + false + ); GeneralUtility::setContainer($container); }); diff --git a/Tests/FunctionalTestCase.php b/Tests/FunctionalTestCase.php index 93aecd67e..fde6825dc 100644 --- a/Tests/FunctionalTestCase.php +++ b/Tests/FunctionalTestCase.php @@ -15,6 +15,7 @@ use In2code\In2publishCore\Utility\DatabaseUtility; use Psr\Container\ContainerInterface; use ReflectionProperty; +use RuntimeException; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Cache\Backend\NullBackend; use TYPO3\CMS\Core\Database\ConnectionPool; @@ -60,7 +61,7 @@ abstract class FunctionalTestCase extends \TYPO3\TestingFramework\Core\Functiona * This method should be called with parent::setUp() in your test cases! * * @return void - * @throws \Doctrine\DBAL\DBALException + * @throws DBALException */ protected function setUp(): void { @@ -87,9 +88,9 @@ protected function setUp(): void // sqlite db path preparation $dbPathSqlite = dirname($this->instancePath) . '/functional-sqlite-dbs/test_' . $this->identifier . '.sqlite'; $dbPathSqliteEmpty = dirname($this->instancePath) - . '/functional-sqlite-dbs/test_' - . $this->identifier - . '.empty.sqlite'; + . '/functional-sqlite-dbs/test_' + . $this->identifier + . '.empty.sqlite'; $localConfiguration = ['DB' => ['Connections' => []]]; $connections = &$localConfiguration['DB']['Connections']; @@ -248,7 +249,7 @@ protected function setUp(): void protected function getContainer(): ContainerInterface { if (!$this->container instanceof ContainerInterface) { - throw new \RuntimeException('Please invoke parent::setUp() before calling getContainer().', 1589221777); + throw new RuntimeException('Please invoke parent::setUp() before calling getContainer().', 1589221777); } return $this->container; } diff --git a/Tests/Unit/Domain/Model/RecordTest.php b/Tests/Unit/Domain/Model/RecordTest.php index 59656763c..3ef54cde0 100644 --- a/Tests/Unit/Domain/Model/RecordTest.php +++ b/Tests/Unit/Domain/Model/RecordTest.php @@ -23,9 +23,9 @@ class RecordTest extends UnitTestCase protected function getRecordStub($getIgnoreFields, bool $isParentRecordDisabled = false): Record { $stub = $this->getMockBuilder(Record::class) - ->setMethods(['getIgnoreFields', 'isParentDisabled']) - ->disableOriginalConstructor() - ->getMock(); + ->setMethods(['getIgnoreFields', 'isParentDisabled']) + ->disableOriginalConstructor() + ->getMock(); $stub->method('getIgnoreFields')->will($this->returnValue($getIgnoreFields)); $stub->method('isParentDisabled')->will($this->returnValue($isParentRecordDisabled)); @@ -1012,9 +1012,9 @@ public function testGetStateRecursiveChecksEachRecordOnce() /** @var Record|MockObject $stub1 */ $stub1 = $this->getMockBuilder(Record::class) - ->setMethods(['getIgnoreFields', 'isParentDisabled', 'isChanged']) - ->disableOriginalConstructor() - ->getMock(); + ->setMethods(['getIgnoreFields', 'isParentDisabled', 'isChanged']) + ->disableOriginalConstructor() + ->getMock(); $stub1->method('getIgnoreFields')->will($this->returnValue([])); $stub1->method('isParentDisabled')->will($this->returnValue(false)); $stub1->__construct('tt_content', ['uid' => 1], ['uid' => 1], [], []); @@ -1023,9 +1023,9 @@ public function testGetStateRecursiveChecksEachRecordOnce() /** @var Record|MockObject $stub2 */ $stub2 = $this->getMockBuilder(Record::class) - ->setMethods(['getIgnoreFields', 'isParentDisabled', 'isChanged']) - ->disableOriginalConstructor() - ->getMock(); + ->setMethods(['getIgnoreFields', 'isParentDisabled', 'isChanged']) + ->disableOriginalConstructor() + ->getMock(); $stub2->method('getIgnoreFields')->will($this->returnValue([])); $stub2->method('isParentDisabled')->will($this->returnValue(false)); $stub2->__construct('tt_content', ['uid' => 2], ['uid' => 2], [], []); diff --git a/Tests/Unit/Utility/BackendUtilityTest.php b/Tests/Unit/Utility/BackendUtilityTest.php index 94328cab3..6a3c416ce 100644 --- a/Tests/Unit/Utility/BackendUtilityTest.php +++ b/Tests/Unit/Utility/BackendUtilityTest.php @@ -319,7 +319,7 @@ public function testGetPageIdentifierReturnsPidFromArgumentsIfTableIsPages() public function testGetPageIdentifierReturnsZeroIfAnyMethodFails() { $this->rows = [ - ['uid' => 321] + ['uid' => 321], ]; $this->assertSame(0, BackendUtility::getPageIdentifier(321, 'tt_content')); From 44b816892febf904353c81d03b6330d59de8cac4 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 3 May 2022 17:50:26 +0200 Subject: [PATCH 49/56] [DOCS] Add missing Event descriptions, reformat all files --- ...eprecation-BaseRepositoryTableNameField.md | 15 ++-- ...-BaseRepositoryIdentifierFieldNameField.md | 13 +++- ...n-CommonRepositoryConvertToRecordMethod.md | 7 +- .../47934-Deprecation-OldTaskClasses.md | 4 + ...cation-TcaProcessingServiceStaticAccess.md | 1 + .../Events/DetermineIfRecordIsPublishing.md | 45 +++++++++++ Documentation/Events/FolderWasPublished.md | 6 +- .../Events/RecordWasCreatedForDetailAction.md | 16 ++++ Documentation/Events/RecordWasEnriched.md | 1 - .../Events/RecordWasSelectedForPublishing.md | 6 +- .../RecordsWereSelectedForPublishing.md | 43 +++++++++++ .../Events/RelatedRecordsByRteWereFetched.md | 13 +++- Documentation/FAQ.md | 50 +++++++----- .../Features/ContextMenuPublishEntry.md | 12 +-- Documentation/Features/RedirectsSupport.md | 11 ++- Documentation/Features/WarningOnLive.md | 13 ++-- Documentation/Guides/CustomTasks.md | 40 ++++++---- Documentation/Guides/CustomTools.md | 9 ++- Documentation/Guides/DynamicConfiguration.md | 8 +- Documentation/Guides/README.md | 3 +- Documentation/Installation/1_Preparation.md | 13 ++-- Documentation/Installation/2_Installation.md | 21 ++--- Documentation/Installation/3_Configuration.md | 66 +++++++++------- Documentation/Installation/4_Testing.md | 9 ++- Documentation/Introduction.md | 11 ++- Documentation/KnownIssues.md | 9 ++- Documentation/Manual/Introduction.md | 10 ++- Documentation/RequirementsAndLimitations.md | 76 +++++++++++++------ .../Use/TheSimpleWay/PublishFiles.md | 16 ++-- .../Use/TheSimpleWay/PublishOverview.md | 8 +- Documentation/Use/TheSimpleWay/README.md | 4 +- 31 files changed, 398 insertions(+), 161 deletions(-) create mode 100644 Documentation/Events/DetermineIfRecordIsPublishing.md create mode 100644 Documentation/Events/RecordWasCreatedForDetailAction.md create mode 100644 Documentation/Events/RecordsWereSelectedForPublishing.md diff --git a/Documentation/Changelog/36213-Deprecation-BaseRepositoryTableNameField.md b/Documentation/Changelog/36213-Deprecation-BaseRepositoryTableNameField.md index 7f51cfedb..f8e1547ba 100644 --- a/Documentation/Changelog/36213-Deprecation-BaseRepositoryTableNameField.md +++ b/Documentation/Changelog/36213-Deprecation-BaseRepositoryTableNameField.md @@ -14,11 +14,15 @@ Deprecated Methods: 1. Access to the field is deprecated. (`\In2code\In2publishCore\Domain\Repository\BaseRepository::getTableName`) 1. Changing the field value is deprecated. (`\In2code\In2publishCore\Domain\Repository\BaseRepository::setTableName`) -1. Replacing the field value is deprecated. (`\In2code\In2publishCore\Domain\Repository\BaseRepository::replaceTableName`) -1. Instantiation of `CommonRepository` with a `tableName` is deprecated. (`\In2code\In2publishCore\Domain\Repository\CommonRepository::__construct`) -1. Calling `CommonRepository::getDefaultInstance` with a `tableName` is deprecated. (`\In2code\In2publishCore\Domain\Repository\CommonRepository::getDefaultInstance`) +1. Replacing the field value is + deprecated. (`\In2code\In2publishCore\Domain\Repository\BaseRepository::replaceTableName`) +1. Instantiation of `CommonRepository` with a `tableName` is + deprecated. (`\In2code\In2publishCore\Domain\Repository\CommonRepository::__construct`) +1. Calling `CommonRepository::getDefaultInstance` with a `tableName` is + deprecated. (`\In2code\In2publishCore\Domain\Repository\CommonRepository::getDefaultInstance`) Other changes: + 1. The signal `shouldSkipFindByIdentifier` now passes the `tableName` as part of the signal arguments. ## Affected Installations @@ -27,5 +31,6 @@ All. ## Migration -Remove any call to `replaceTableName`, `setTableName` and `getTableName`, remove the `tableName` from any `CommonRepository` constructor or factory method. -Add the `tableName` to any method that requires it optionally. You will find these method names in the deprecation log. +Remove any call to `replaceTableName`, `setTableName` and `getTableName`, remove the `tableName` from +any `CommonRepository` constructor or factory method. +Add the `tableName` to any method that requires it optionally. You will find these method names in the deprecation log. diff --git a/Documentation/Changelog/36219-Deprecation-BaseRepositoryIdentifierFieldNameField.md b/Documentation/Changelog/36219-Deprecation-BaseRepositoryIdentifierFieldNameField.md index 0faa36f06..fc676c98d 100644 --- a/Documentation/Changelog/36219-Deprecation-BaseRepositoryIdentifierFieldNameField.md +++ b/Documentation/Changelog/36219-Deprecation-BaseRepositoryIdentifierFieldNameField.md @@ -11,8 +11,11 @@ A refactoring to ease the usage of the repository methods, especially of the der ## Impact Deprecated Methods: -1. Access to the field is deprecated. (`\In2code\In2publishCore\Domain\Repository\BaseRepository::getIdentifierFieldName`) -1. Instantiation of `CommonRepository` with an `identifierFieldName` is deprecated. (`\In2code\In2publishCore\Domain\Repository\CommonRepository::__construct`) + +1. Access to the field is + deprecated. (`\In2code\In2publishCore\Domain\Repository\BaseRepository::getIdentifierFieldName`) +1. Instantiation of `CommonRepository` with an `identifierFieldName` is + deprecated. (`\In2code\In2publishCore\Domain\Repository\CommonRepository::__construct`) 1. `findByIdentifierInOtherTable` is deprecated as it does the exact same as `findByIdentifier` ## Affected Installations @@ -24,5 +27,7 @@ All. Remove any call to `getIdentifierFieldName`. Do not instantiate the `CommonRepository` with an `identifierFieldName`. -If you extended the `BaseRepository` or `CommonRepository` you should consider using public methods provided by these classes. -If that is not possible for your use case feel free to provide a pull request with a new signal or added optional arguments. +If you extended the `BaseRepository` or `CommonRepository` you should consider using public methods provided by these +classes. +If that is not possible for your use case feel free to provide a pull request with a new signal or added optional +arguments. diff --git a/Documentation/Changelog/36641-Depreaction-CommonRepositoryConvertToRecordMethod.md b/Documentation/Changelog/36641-Depreaction-CommonRepositoryConvertToRecordMethod.md index dbf75e0cf..5bcc471a8 100644 --- a/Documentation/Changelog/36641-Depreaction-CommonRepositoryConvertToRecordMethod.md +++ b/Documentation/Changelog/36641-Depreaction-CommonRepositoryConvertToRecordMethod.md @@ -12,6 +12,7 @@ This method is therefore only an anemic wrapper around `RecordFactory::makeInsta ## Impact Deprecated Methods: + 1. Calling the method `\In2code\In2publishCore\Domain\Repository\CommonRepository::convertToRecord` is deprecated. ## Affected Installations @@ -29,5 +30,7 @@ $this->recordFactory->makeInstance($this, $localProperties, $foreignProperties, Do not instantiate the `CommonRepository` with an `identifierFieldName`. -If you extended the `BaseRepository` or `CommonRepository` you should consider using public methods provided by these classes. -If that is not possible for your use case feel free to provide a pull request with a new signal or added optional arguments. +If you extended the `BaseRepository` or `CommonRepository` you should consider using public methods provided by these +classes. +If that is not possible for your use case feel free to provide a pull request with a new signal or added optional +arguments. diff --git a/Documentation/Changelog/47934-Deprecation-OldTaskClasses.md b/Documentation/Changelog/47934-Deprecation-OldTaskClasses.md index 567fdc459..45d6b0141 100644 --- a/Documentation/Changelog/47934-Deprecation-OldTaskClasses.md +++ b/Documentation/Changelog/47934-Deprecation-OldTaskClasses.md @@ -27,17 +27,21 @@ All. If you extend or inject any of these classes then please update your dependency or parent to the new class. RunTasksInQueueCommand: + * Old: `\In2code\In2publishCore\Command\Foreign\PublishTaskRunner\RunTasksInQueueCommand` * New: `\In2code\In2publishCore\Component\PostPublishTaskExecution\Command\Foreign\RunTasksInQueueCommand` TaskRepository: + * Old: `\In2code\In2publishCore\Domain\Repository\TaskRepository` * New: `\In2code\In2publishCore\Component\PostPublishTaskExecution\Domain\Repository\TaskRepository` TaskFactory: + * Old: `\In2coe\In2publishCore\Domain\Factory\TaskFactory` * New: `\In2code\In2publishCore\Component\PostPublishTaskExecution\Domain\Factory\TaskFactory` AbstractTask: + * Old: `\In2code\In2publishCore\Domain\Model\Task\AbstractTask` * New: `\In2code\In2publishCore\Component\PostPublishTaskExecution\Domain\Model\Task\AbstractTask` diff --git a/Documentation/Changelog/48403-Deprecation-TcaProcessingServiceStaticAccess.md b/Documentation/Changelog/48403-Deprecation-TcaProcessingServiceStaticAccess.md index fa799855d..5fdad7cd4 100644 --- a/Documentation/Changelog/48403-Deprecation-TcaProcessingServiceStaticAccess.md +++ b/Documentation/Changelog/48403-Deprecation-TcaProcessingServiceStaticAccess.md @@ -11,6 +11,7 @@ deprecates all static methods of the class and introduces non-static methods for ## Impact Following methods are deprecated: + * `\In2code\In2publishCore\Domain\Service\TcaProcessingService::getIncompatibleTca` * `\In2code\In2publishCore\Domain\Service\TcaProcessingService::getCompatibleTca` * `\In2code\In2publishCore\Domain\Service\TcaProcessingService::getControls` diff --git a/Documentation/Events/DetermineIfRecordIsPublishing.md b/Documentation/Events/DetermineIfRecordIsPublishing.md new file mode 100644 index 000000000..965440f97 --- /dev/null +++ b/Documentation/Events/DetermineIfRecordIsPublishing.md @@ -0,0 +1,45 @@ +# DetermineIfRecordIsPublishing + +**internal** + +_since 10.2.3, 11.0.2_ + +## When + +This event is dispatched fairly often. It is, as the name states, used to determine if a record is currently being +published by another process. The information is held in a database table, which is one of the few things shared between +processes. This event might be removed. + +After isPublishing was set to `true`, no other listeners will be invoked. The determination can not be reversed. + +## What + +* `publishing`: A bool indicating if the record is publishing (`true`) or not publishing (`false`) +* `tableName`: The record's table name +* `identifier`: The record's uid or compoined identifier. The type is `int` in most cases, but can be `string` if the + record is an MM table entry. + +## Possibilities + +If you use a special publisher that does not lead to the record being recognized by the `RunningRequestsService`, you +have the possibility to mark each record as "currently being published" by means of your own listener. + +### Example + +```php +use In2code\In2publishCore\Event\DetermineIfRecordIsPublishing; + +class PublishingStateService +{ + protected $inPublishing = []; + + public function __invoke(DetermineIfRecordIsPublishing $event): void + { + $table = $event->getTableName(); + $identifier = $event->getIdentifier(); + if (isset($this->inPublishing[$table][$identifier])) { + $event->setIsPublishing(); + } + } +} +``` diff --git a/Documentation/Events/FolderWasPublished.md b/Documentation/Events/FolderWasPublished.md index 30ed6c7f2..876ec1fe7 100644 --- a/Documentation/Events/FolderWasPublished.md +++ b/Documentation/Events/FolderWasPublished.md @@ -9,12 +9,14 @@ Every time a folder was published, regardless of the success. ## What * `storage`: The storage identifier which contains the folder. -* `folderIdentifier`: The folder identifier inside the storage. This is usually the full relative path to the folder (in fileadmin). +* `folderIdentifier`: The folder identifier inside the storage. This is usually the full relative path to the folder (in + fileadmin). * `success`: A bool to indicate if the publishing was successful or not. ## Possibilities -You can listen on this event to publish additional information associated with the folder (like in2publish does for EXT:fal_securedownload) +You can listen on this event to publish additional information associated with the folder (like in2publish does for EXT: +fal_securedownload) ### Example diff --git a/Documentation/Events/RecordWasCreatedForDetailAction.md b/Documentation/Events/RecordWasCreatedForDetailAction.md new file mode 100644 index 000000000..ff37e9a51 --- /dev/null +++ b/Documentation/Events/RecordWasCreatedForDetailAction.md @@ -0,0 +1,16 @@ +# RecordWasCreatedForDetailAction + +Replaces the `\In2code\In2publishCore\Controller\RecordController / beforeDetailViewRender` Signal. + +## When + +Every time in `\In2code\In2publishCore\Controller\RecordController::detailAction`. + +## What + +* `recordController`: The instance of the RecordController executing the request. +* `record`: The record found for the current request. + +## Possibilities + +Use this event if you want to observe the record before it will be rendered by the view. diff --git a/Documentation/Events/RecordWasEnriched.md b/Documentation/Events/RecordWasEnriched.md index 17428e697..c7782f587 100644 --- a/Documentation/Events/RecordWasEnriched.md +++ b/Documentation/Events/RecordWasEnriched.md @@ -6,7 +6,6 @@ NOTE: this event is deprecated and will be removed in in2publish_core version 11 ## When - ## What * `record`: A fully resolved instance of the record. diff --git a/Documentation/Events/RecordWasSelectedForPublishing.md b/Documentation/Events/RecordWasSelectedForPublishing.md index d58d8393b..3260bb812 100644 --- a/Documentation/Events/RecordWasSelectedForPublishing.md +++ b/Documentation/Events/RecordWasSelectedForPublishing.md @@ -2,12 +2,16 @@ Replaces the `\In2code\In2publishCore\Controller\RecordController / beforePublishing` Signal. - ## When +This event will be dispatched when a record in the Publish Overview Module has been selected for publishing. ## What + * `recordController`: The record controller which was used to execute the request. * `record`: A fully resolved instance of the record. ## Possibilities + +You can inspect/alter the record. If you want to listen for records that will be published regardless of the view where +they were selected you can use [`RecursiveRecordPublishingBegan` (link)](RecursiveRecordPublishingBegan.md) instead. diff --git a/Documentation/Events/RecordsWereSelectedForPublishing.md b/Documentation/Events/RecordsWereSelectedForPublishing.md new file mode 100644 index 000000000..5239ab624 --- /dev/null +++ b/Documentation/Events/RecordsWereSelectedForPublishing.md @@ -0,0 +1,43 @@ +# RecordsWereSelectedForPublishing + +_since 10.2.3, 11.0.2_ + +## When + +As of version 10.2.3 and 11.0.2, the event is used when publishing multiple redirects in the Publish Redirect Module at +once. The Content Publisher will mark all records from the event as being published before starting to publish each +record one after another. +All records selected for publishing will instantly be marked as being published. This prevents that during long-running +requests, a record of the selected records will not be publishable by another editor. + +## What + +* `records`: An array of records selected for a batch publishing action. + +## Possibilities + +Use this event if you implement your own batch publishing method. + +### Example + +```php +use In2code\In2publishCore\Domain\Model\RecordInterface; +use In2code\In2publishCore\Event\RecordsWereSelectedForPublishing; +use Symfony\Component\EventDispatcher\EventDispatcher; + +class PublishingStateService +{ + /** @var EventDispatcher */ + protected $eventDispatcher; + + /** + * @param array $records + * @return void + */ + public function publishBatchAction(array $records): void + { + $this->eventDispatcher->dispatch(new RecordsWereSelectedForPublishing($records)); + // ... actually publish the records + } +} +``` diff --git a/Documentation/Events/RelatedRecordsByRteWereFetched.md b/Documentation/Events/RelatedRecordsByRteWereFetched.md index c8ca0b76d..1956e32cf 100644 --- a/Documentation/Events/RelatedRecordsByRteWereFetched.md +++ b/Documentation/Events/RelatedRecordsByRteWereFetched.md @@ -4,10 +4,19 @@ Replaces the `\In2code\In2publishCore\Repository\CommonRepository / relationReso ## When - +Each time after the Content Publisher tried to resolve relations to records that are embedded in RichText or t3 URIs, +regardless whether one or more records have been found or not. ## What - +* `recordFinder`: The instance of the `\In2code\In2publishCore\Component\RecordHandling\RecordFinder` which tried to + resolve the relations. +* `bodyText`: The text that was examined by the RecordFinder +* `excludedTableNames`: The current list of table names which are excluded +* `relatedRecords`: All records found by the RecordFinder. Can be empty. ## Possibilities + +This signal has been used primarily to extend the search methods with other algorithms, that detect relations based on +different clues in the text, e.g. embedded images. Records added to the event will be added to the list of found +records. diff --git a/Documentation/FAQ.md b/Documentation/FAQ.md index cd49044c5..94752f98e 100644 --- a/Documentation/FAQ.md +++ b/Documentation/FAQ.md @@ -20,10 +20,11 @@ for details ## How to delete caches of a page in production? in2publish (Enterprise Version) includes the Remote Cache Control (short: RCC) feature. -This allows you to clear specific caches on remote as easy an configurable as the clear cache controls in you Local's backend. +This allows you to clear specific caches on remote as easy an configurable as the clear cache controls in you Local's +backend. If you publish a page, frontend-caches of the same page on production will be cleaned. -Special case: For sysfolders, e.g. with news-records, you want to clean the cache of another page than the sysfolder +Special case: For sysfolders, e.g. with news-records, you want to clean the cache of another page than the sysfolder that was published. In this case you can use clearCacheCmd in Page TSConfig on the stage (!) system: # Put this page TSConfig on a news sysfolder. Any publish of this sysfolder will clean FE-cache of PID 12 and 23 @@ -47,8 +48,10 @@ Example call with environment variable (for the stage system): ## Where can i get the Foreign Key Fingerprint -The Foreign Key Fingerprint is, as the name states, a hash of the public ssh key from the **foreign** system's ssh server. -You can generate the hash with following command on your **foreign** server (example command!): `ssh-keygen -E md5 -lf /etc/ssh/ssh_host_rsa_key.pub` +The Foreign Key Fingerprint is, as the name states, a hash of the public ssh key from the **foreign** system's ssh +server. +You can generate the hash with following command on your **foreign** server (example +command!): `ssh-keygen -E md5 -lf /etc/ssh/ssh_host_rsa_key.pub` Hint: @@ -67,24 +70,37 @@ Go to "System Preferences" -> "Internet & Networking" -> "Sharing" -> enable "Re ## How can i publish content from Live to Stage? You can't (kind of). -If you want to transfer user generated content from Live to Stage you can use the TableCommandController (available in the Scheduler for example) or write your own scripts. -But be aware that the table:import command overwrites one table with another. It does not keep relations (it does not even resolve them) and it does not merge data. It is just a simple and stupid table copy task. +If you want to transfer user generated content from Live to Stage you can use the TableCommandController (available in +the Scheduler for example) or write your own scripts. +But be aware that the table:import command overwrites one table with another. It does not keep relations (it does not +even resolve them) and it does not merge data. It is just a simple and stupid table copy task. ## How do i handle user generated content? **CAUTION: in2publish_core does not handle user generated content. If record UIDs match any data will be overwritten!** -The TYPO3 core does not provide a frontend user image upload or any other plugin that enables frontend users to create, update or remove data, therefore any implementation is a 3rd party extension. +The TYPO3 core does not provide a frontend user image upload or any other plugin that enables frontend users to create, +update or remove data, therefore any implementation is a 3rd party extension. Please note that we can not provide generic ("out-of-the-box") support for any 3rd party extension. -If you have problems with a specific 3rd party extension you can contact [service@in2code.de](mailto:service@in2code.de) to ask for a consulting/support quote. +If you have problems with a specific 3rd party extension you can contact [service@in2code.de](mailto:service@in2code.de) +to ask for a consulting/support quote. First of all: Ensure all tables that are affected by user generated content are included in `excludeRelatedTables`. -Some tables like `sys_file`, `sys_file_reference` and `sys_file_metadata`, however, must not be included in `excludeRelatedTables` or publishing content with images will not work. -Since these tables are also affected by frontend user interaction on live (if there is an image upload or a forum or something like that [3rd party!]) there will be conflicts. -These conflicts will lead to user content in published content or vice versa. **Be aware that unhandled conflicts might lead to data disclosure!** - -**There is, however an experimental feature**, which allows you to have user generated content without running into UID conflicts. -First of all set `factory.fal.reserveSysFileUids` to FALSE. The you have to set the auto_increment of the tables `sys_file`, `sys_file_reference` and `sys_file_metadata` to a high value on foreign (and only on foreign!). -The distance between the local and foreign auto_increment denominates the number of entries, which can be created on the local system. In case you set the auto_increment too low (e.g. 1000) you will run into conflicts very soon, if you set it too high (e.g. 2147483547) you will soon run out of possible UIDs on foreign (on 32-bit systems). -There is still one thing you must know: When using this feature UIDs of sys_file records may be rewritten, so you might loose any data from the foreign instance related to that record. -This should only happen if there are two indices for the exact same file with different UIDs, so this case is rather rare. +Some tables like `sys_file`, `sys_file_reference` and `sys_file_metadata`, however, must not be included +in `excludeRelatedTables` or publishing content with images will not work. +Since these tables are also affected by frontend user interaction on live (if there is an image upload or a forum or +something like that [3rd party!]) there will be conflicts. +These conflicts will lead to user content in published content or vice versa. **Be aware that unhandled conflicts might +lead to data disclosure!** + +**There is, however an experimental feature**, which allows you to have user generated content without running into UID +conflicts. +First of all set `factory.fal.reserveSysFileUids` to FALSE. The you have to set the auto_increment of the +tables `sys_file`, `sys_file_reference` and `sys_file_metadata` to a high value on foreign (and only on foreign!). +The distance between the local and foreign auto_increment denominates the number of entries, which can be created on the +local system. In case you set the auto_increment too low (e.g. 1000) you will run into conflicts very soon, if you set +it too high (e.g. 2147483547) you will soon run out of possible UIDs on foreign (on 32-bit systems). +There is still one thing you must know: When using this feature UIDs of sys_file records may be rewritten, so you might +loose any data from the foreign instance related to that record. +This should only happen if there are two indices for the exact same file with different UIDs, so this case is rather +rare. diff --git a/Documentation/Features/ContextMenuPublishEntry.md b/Documentation/Features/ContextMenuPublishEntry.md index dad39fa89..23de0de55 100644 --- a/Documentation/Features/ContextMenuPublishEntry.md +++ b/Documentation/Features/ContextMenuPublishEntry.md @@ -1,15 +1,17 @@ # Feature: Context Menu Publish Entry (`features.contextMenuPublishEntry.enable`) -Adds a new entry to the page tree tight click menu, which allows you to publish the page without opening the publishing module. -Please note, that the option to publish is not restricted to the actual state of the record, because the state calculation requires a lot of resources. -This feature has an integration in the Content Publisher Enterprise Edition, which will hide the context menu entry when the page is not "Ready to publish". +Adds a new entry to the page tree tight click menu, which allows you to publish the page without opening the publishing +module. Please note, that the option to publish is not restricted to the actual state of the record, because the state +calculation requires a lot of resources. This feature has an integration in the Content Publisher Enterprise Edition, +which will hide the context menu entry when the page is not "Ready to publish". Please read the [Known Issues Documentation](../KnownIssues.md) before activation. Enable the feature: + ```YAML features: - contextMenuPublishEntry: - enable: TRUE + contextMenuPublishEntry: + enable: TRUE ``` ![Publish Page via context menu](_img/context_menu_publish_entry.png) diff --git a/Documentation/Features/RedirectsSupport.md b/Documentation/Features/RedirectsSupport.md index 0ef7b6453..5f46b368b 100644 --- a/Documentation/Features/RedirectsSupport.md +++ b/Documentation/Features/RedirectsSupport.md @@ -2,13 +2,16 @@ TYPO3 has a feature that editors can use to set up and maintain redirects. This new feature "Redirects Support" is available so that these redirects can also be published. -If the support of the redirects is activated, a new module appears in the backend and two new fields for the redirects themselves. -With the module, specific redirects can be published individually or selected together. +If the support of the redirects is activated, a new module appears in the backend and two new fields for the redirects +themselves. With the module, specific redirects can be published individually or selected together. -Forwardings are created and maintained on the local system with the local domain. In order for these to work on the remote system, the content publisher must know the name of the corresponding domain on the remote system. This association is either set directly on the site configuration of the remote system or on a page in the local page tree. +Forwardings are created and maintained on the local system with the local domain. In order for these to work on the +remote system, the content publisher must know the name of the corresponding domain on the remote system. This +association is either set directly on the site configuration of the remote system or on a page in the local page tree. If a page has been selected, the forwarding will be published together with the page. -When a redirect is associated with a page, the page must be published so that the content publisher can determine the domain on the remote system. +When a redirect is associated with a page, the page must be published so that the content publisher can determine the +domain on the remote system. If forwarding is not restricted to a domain, no site configuration or page association is required. diff --git a/Documentation/Features/WarningOnLive.md b/Documentation/Features/WarningOnLive.md index 4c937693d..bfde90063 100644 --- a/Documentation/Features/WarningOnLive.md +++ b/Documentation/Features/WarningOnLive.md @@ -11,10 +11,13 @@ The status bar color should indicate that the system is Foreign. ![Colorized Header on Foreign](_img/colorized_header_foreign.png "The TYPO3 status bar is inked in an orange color to indicate that the instance is Foreign") -You can enable this feature by setting `features.warningOnForeign.colorizeHeader.enable = TRUE` in your **ForeignConfiguration.yaml on Foreign** -The color can be changed with the setting `features.warningOnForeign.colorizeHeader.color`. -Allowed values for `color` are generally speaking all color-ish values accepted by the css option `background-color` which represent a color. -E.g. Hex values like `#aaa` or `#ab6f8s`, RGB/A `rgb(255, 0, 0)` or `rgba(156, 153, 12, 0.42)` or color names like `red`, `blue` or `black`. -You can find a full list of allowed color names in the property `\In2code\In2publishCore\Features\WarningOnForeign\Config\Validator\CssColorValueValidator::$colorNames` +* You can enable this feature by setting `features.warningOnForeign.colorizeHeader.enable = TRUE` in your ** + ForeignConfiguration.yaml on Foreign**. +* The color can be changed with the setting `features.warningOnForeign.colorizeHeader.color`. +* Allowed values for `color` are generally speaking all color-ish values accepted by the css option `background-color` + which represent a color. E.g. Hex values like `#aaa` or `#ab6f8s`, RGB/A `rgb(255, 0, 0)` + or `rgba(156, 153, 12, 0.42)` or color names like `red`, `blue` or `black`. +* You can find a full list of allowed color names in the + property `\In2code\In2publishCore\Features\WarningOnForeign\Config\Validator\CssColorValueValidator::$colorNames` Additional ways of warning editors might be implemented in the future. They will be documented here. diff --git a/Documentation/Guides/CustomTasks.md b/Documentation/Guides/CustomTasks.md index a228c174b..fd4b62bdf 100644 --- a/Documentation/Guides/CustomTasks.md +++ b/Documentation/Guides/CustomTasks.md @@ -1,7 +1,8 @@ # Custom Tasks **Publishing Tasks** are pieces of code that are executed after the publishing process. -They are different from other executed code by the fact that the context of the execution is on foreign, hence you access the foreign database, access foreign's FAL, and run with foreign's configuration. +They are different from other executed code by the fact that the context of the execution is on foreign, hence you +access the foreign database, access foreign's FAL, and run with foreign's configuration. With the help of "custom tasks" you can tell the foreign system to perform actions after you have published records. ## How does it work? @@ -36,7 +37,8 @@ class MyTask extends \In2code\In2publishCore\Component\PostPublishTaskExecution\ } ``` -Most of the time, you want to add a task when a specific record was published. You can achieve this by using the `register` method as an event listener. +Most of the time, you want to add a task when a specific record was published. You can achieve this by using +the `register` method as an event listener. **Services.yaml** @@ -49,7 +51,8 @@ Most of the time, you want to add a task when a specific record was published. Y event: In2code\In2publishCore\Event\PublishingOfOneRecordEnded ``` -When a record was published, the `register` method will be called. We can not filter for specific record, e.g. for a table and property. +When a record was published, the `register` method will be called. We can not filter for specific record, e.g. for a +table and property. ```PHP use In2code\In2publishCore\Component\PostPublishTaskExecution\Domain\Model\Task\AbstractTask;use In2code\In2publishCore\Event\PublishingOfOneRecordEnded; @@ -76,11 +79,14 @@ class MyTask extends AbstractTask } ``` -BTW: This is not a good class design. The responsibility of the Task is to execute code on foreign, not to register itself. You should use an anomaly for that (described later on). +BTW: This is not a good class design. The responsibility of the Task is to execute code on foreign, not to register +itself. You should use an anomaly for that (described later on). **Attention: You can register Tasks multiple times. -If you use a signal that is fired for each published record you might end up with thousands of tasks registered during the publishing process. -These tasks will be executed on foreign and can temporarily adversely affect performance and make the publishing process very slow.** +If you use a signal that is fired for each published record you might end up with thousands of tasks registered during +the publishing process. +These tasks will be executed on foreign and can temporarily adversely affect performance and make the publishing process +very slow.** Events that are suited for task registration because they are fired once are: @@ -90,14 +96,18 @@ Events that are suited for task registration because they are fired once are: ## Collect data -Tasks are used to flush caches, refresh indices or to do other things that are not covered by the sole process of writing records to the foreign database. -Most tasks require a configuration, e.g. the `FlushFrontendPageCacheTask` needs to know all affected PIDs to clear the caches for these pages. -in2publish_core utilizes so called _Anomalies_ to collect relevant data during the publishing process (Anomalies were originally intended to publish non-database information/stuff like files). +Tasks are used to flush caches, refresh indices or to do other things that are not covered by the sole process of +writing records to the foreign database. +Most tasks require a configuration, e.g. the `FlushFrontendPageCacheTask` needs to know all affected PIDs to clear the +caches for these pages. +in2publish_core utilizes so called _Anomalies_ to collect relevant data during the publishing process (Anomalies were +originally intended to publish non-database information/stuff like files). Basically you need to implement three parts: 1. **Create the anomaly** (must be a `Singleton` to work correctly) -1. **Connect the anomaly to the signals** that provide the required information e.g. by utilizing the signal "publishRecordRecursiveBeforePublishing" you can collect data about all published records. +1. **Connect the anomaly to the signals** that provide the required information e.g. by utilizing the signal " + publishRecordRecursiveBeforePublishing" you can collect data about all published records. 1. **Create a Task** that will be registered During runtime your code has to: @@ -111,7 +121,9 @@ During runtime your code has to: #### Collector Class (Anomaly) This class will collect all data you will use in your task. -It is wise to only collect information your tasks requires. Do not `clone` records. If you need to memorize the publishing state of a record (that will change during the publishing process) save it in an array next to the record. (Variables containing objects "point" to the object and do not require a lot of memory). +It is wise to only collect information your tasks requires. Do not `clone` records. If you need to memorize the +publishing state of a record (that will change during the publishing process) save it in an array next to the record. ( +Variables containing objects "point" to the object and do not require a lot of memory). The method `collectInfo` is called by the signal dispatcher. ```PHP @@ -153,7 +165,8 @@ class MyAnomaly implements SingletonInterface #### Event Listener * The event `\In2code\In2publishCore\Event\PublishingOfOneRecordBegan` will be fired for each record being published. -* The event `\In2code\In2publishCore\Event\RecursiveRecordPublishingEnded` will be fired once after publishing. You can leverage it to finally create your task. +* The event `\In2code\In2publishCore\Event\RecursiveRecordPublishingEnded` will be fired once after publishing. You can + leverage it to finally create your task. Remove the task self-registration from your Services.yaml and use the anomaly instead: @@ -198,4 +211,5 @@ class MyTask extends \In2code\In2publishCore\Component\PostPublishTaskExecution\ } ``` -Notice that this class does not register itself, since it's not the tasks responsibility. Its only responsibility is to execute steps on the foreign system based on its configuration. +Notice that this class does not register itself, since it's not the tasks responsibility. Its only responsibility is to +execute steps on the foreign system based on its configuration. diff --git a/Documentation/Guides/CustomTools.md b/Documentation/Guides/CustomTools.md index 49b36e3ca..bed7f9d02 100644 --- a/Documentation/Guides/CustomTools.md +++ b/Documentation/Guides/CustomTools.md @@ -9,15 +9,18 @@ The tag has the following properties: title or a splitLabel. * `description`: The description that identifies the tool and is shown in the Publish Tools Module. The value is either the title or a splitLabel. -* `actions`: An comma separated list of controller action names (The methods of your controller which should be callable). The first +* `actions`: An comma separated list of controller action names (The methods of your controller which should be + callable). The first action is the default action which will be called when the Tool was selected. * (optional) `condition`: A condition that has to evaluate to true. The condition parts are delimited by `:` (colons) - * `CONF`: A dot-path to the configuration value e.g. `CONF:features.remoteCacheControl.enableTool` - * `EXTCONF`: This condition has three parts. `EXTCONF`, an extension key and a path to the extension's config e.g. `EXTCONF:in2publish:managedSettings` + * `CONF`: A dot-path to the configuration value e.g. `CONF:features.remoteCacheControl.enableTool` + * `EXTCONF`: This condition has three parts. `EXTCONF`, an extension key and a path to the extension's config + e.g. `EXTCONF:in2publish:managedSettings` * (optional) `before`: A comma separated list of services which must appear after this service. * (optional) `after`: A comma separated list of services which must appear before this service. Example `Services.yaml` (taken from the Enterprise Edition): + ```yaml services: In2code\In2publish\Features\RemoteCacheControl\Controller\RemoteCacheController: diff --git a/Documentation/Guides/DynamicConfiguration.md b/Documentation/Guides/DynamicConfiguration.md index 1330d2610..1022e8dff 100644 --- a/Documentation/Guides/DynamicConfiguration.md +++ b/Documentation/Guides/DynamicConfiguration.md @@ -18,10 +18,12 @@ Example: `%env(TYPO3_CONTEXT)%`\ * The percentage signs (`%`) at the beginning and end of the string indicate, that this value is dynamic. * The part `env` before the opening round bracket (`)`) is the provider key. * The contents between the round brackets will be passed to the actual provider and is therefore provider specific. - * The value between the round brackets can contain any character expect a closing round bracket. - * In this example the provider is `env`, which will return the value of the env var `TYPO3_CONTEXT`, e.g. "`Production/Stage`" + * The value between the round brackets can contain any character expect a closing round bracket. + * In this example the provider is `env`, which will return the value of the env var `TYPO3_CONTEXT`, + e.g. "`Production/Stage`" -You can check if your syntax is correct with the regular expression from `DynamicValuesPostProcessor::DYNAMIC_REFERENCE_PATTERN`. +You can check if your syntax is correct with the regular expression +from `DynamicValuesPostProcessor::DYNAMIC_REFERENCE_PATTERN`. (Or visit https://www.phpliveregex.com/p/wzP) ## Custom Provider diff --git a/Documentation/Guides/README.md b/Documentation/Guides/README.md index 1e03ff858..989c64a95 100644 --- a/Documentation/Guides/README.md +++ b/Documentation/Guides/README.md @@ -5,7 +5,8 @@ Guides are in-depth studies of a particular topic. They are intended to fully instruct you about a special concept, feature or how to personalize something in particular. -These guides are written mostly for beginners, but in the end of each guide will be mostly a summary or code collection you can easily adapt for your needs. +These guides are written mostly for beginners, but in the end of each guide will be mostly a summary or code collection +you can easily adapt for your needs. ## Available Guides: diff --git a/Documentation/Installation/1_Preparation.md b/Documentation/Installation/1_Preparation.md index e27ebcb08..b9d59e42a 100644 --- a/Documentation/Installation/1_Preparation.md +++ b/Documentation/Installation/1_Preparation.md @@ -3,7 +3,8 @@ ## Software Requirements **Preface**: -If you do not use `adapter.remote: 'ssh'` or `adapter.transmission: 'ssh'` you can safely ignore any reference to SSH/libssh/php-ssh(2). +If you do not use `adapter.remote: 'ssh'` or `adapter.transmission: 'ssh'` you can safely ignore any reference to +SSH/libssh/php-ssh(2). SSH-Adapters are used by default and they are the only ones shipped with in2publish. If you can't or don't want to use SSH you can ask us for alternatives. @@ -36,16 +37,17 @@ PHP configuration values: |-----------------|---------| | allow_url_fopen | On | - Hint: -> php_ssh2 0.11 does not include the function ssh2_sftp_chmod. You can download a newer version here: [PECL SSH2 Download](https://pecl.php.net/package/ssh2) +> php_ssh2 0.11 does not include the function ssh2_sftp_chmod. You can download a newer version +> here: [PECL SSH2 Download](https://pecl.php.net/package/ssh2) > Most versions on package based server software are below 0.12, so the function has been made optional in in2publish. > In this case you have to take care of file permissions yourself. Hint: -> If you are using xdebug for local development, be sure you set max_nesting_level to at least 5 times of the configuration value factory.maximumOverallRecursion to prevent malfunction of in2publish. +> If you are using xdebug for local development, be sure you set max_nesting_level to at least 5 times of the +> configuration value factory.maximumOverallRecursion to prevent malfunction of in2publish. ## OS Requirements @@ -59,7 +61,8 @@ These requirements are on top of the basic requirements of TYPO3 CMS 7.6 - 8.7 | Keypair | A public and private RSA key pair to authenticate the Webprocess User on Foreign (PW-protected key is supported) | | Environment variable | in2publish requires `SetEnv IN2PUBLISH_CONTEXT Local` to be set in the virtual host or (if allowed) .htaccess | -If Foreign's database is not on the same server (which is not recommended!) you will need a Static port forwarding (from any port on Local to 3306 on Foreign) +If Foreign's database is not on the same server (which is not recommended!) you will need a Static port forwarding (from +any port on Local to 3306 on Foreign) Hint: diff --git a/Documentation/Installation/2_Installation.md b/Documentation/Installation/2_Installation.md index 4b8f3bf75..74584b67f 100644 --- a/Documentation/Installation/2_Installation.md +++ b/Documentation/Installation/2_Installation.md @@ -4,21 +4,16 @@ The installation requires the following steps on both the »Local« and »Foreign« system: 1. Install the extension in TYPO3 - - - Use the Extension Manager, Composer or a copy of the Git repository - - Please take a look at the "in2code GitHub tutorial" if you need more details - + * Use the Extension Manager, Composer or a copy of the Git repository + * Please take a look at the "in2code GitHub tutorial" if you need more details 2. Activate the Extension 3. Set the path to the configuration files of the extension - - The configuration files are created next in the chapter "configuration" - - TYPO3 < 9: Extensions > "in2publish_core" > Button Configure - - TYPO3 >= 9: Settings > Extension Configuration > Button Configure - Extensions > "in2publish_core" - - Change the value `pathToConfiguration` pointing to the configuration file - folder, yet to be created -4. Make sure the environment variable `IN2PUBLISH_CONTEXT` is set, - otherwise the extension modules are not visible - - See [Preparation](1_Preparation.md) + * The configuration files are created next in the chapter "configuration" + * TYPO3 < 9: Extensions > "in2publish_core" > Button Configure + * TYPO3 >= 9: Settings > Extension Configuration > Button Configure Extensions > "in2publish_core" + * Change the value `pathToConfiguration` pointing to the configuration file folder, yet to be created +4. Make sure the environment variable `IN2PUBLISH_CONTEXT` is set, otherwise the extension modules are not visible + * See [Preparation](1_Preparation.md) ## New modules on Local diff --git a/Documentation/Installation/3_Configuration.md b/Documentation/Installation/3_Configuration.md index d797948c4..c1c2e77fd 100644 --- a/Documentation/Installation/3_Configuration.md +++ b/Documentation/Installation/3_Configuration.md @@ -3,36 +3,46 @@ The configuration is split into three parts: * **Extension Configuration** Which defines configuration values so basic they can't be set any later. -* **[LocalConfiguration.yaml](../../Configuration/Yaml/LocalConfiguration.yaml.example)** configuration on Local (Stage) to connect to the production server and configure the modules and behaviour. -* **[ForeignConfiguration.yaml](../../Configuration/Yaml/ForeignConfiguration.yaml.example)** for the configuration on Foreign (production). +* **[LocalConfiguration.yaml](../../Configuration/Yaml/LocalConfiguration.yaml.example)** configuration on Local (Stage) + to connect to the production server and configure the modules and behaviour. +* **[ForeignConfiguration.yaml](../../Configuration/Yaml/ForeignConfiguration.yaml.example)** for the configuration on + Foreign (production). As of in2publish_core 7.0 you don't need to copy the whole file anymore. -You just need to create the file and set values that differ from the default configuration. (Create the file at the location defined in the extension configuration of in2publish_core). +You just need to create the file and set values that differ from the default configuration. (Create the file at the +location defined in the extension configuration of in2publish_core). **Security Notice:** > The Content Publisher uses a YAML file for the configuration. This file is different from PHP files. > YAML files are not executed or processed by the server when called up/opened via an HTTP request. > Instead, most servers send the file as a download to the user who called the URL. -> Please make sure that you prohibit public access to these configuration files via .htaccess, web.config or server configuration (depending on your server). +> Please make sure that you prohibit public access to these configuration files via .htaccess, web.config or server +> configuration (depending on your server). > Example: -> If your configuration file is stored in the folder typo3conf (deprecated), it may be accessible via https://www.yourdomain.tld/typo3conf/LocalConfiguration.yaml +> If your configuration file is stored in the folder typo3conf (deprecated), it may be accessible +> via https://www.yourdomain.tld/typo3conf/LocalConfiguration.yaml Note: -> If you want to separate your configuration depending on the in2publish version, you could also use **LocalConfiguration_[version].yaml** and **ForeignConfiguration_[version].yaml** for a version specific configuration. +> If you want to separate your configuration depending on the in2publish version, you could also use ** +> LocalConfiguration_[version].yaml** and **ForeignConfiguration_[version].yaml** for a version specific configuration. > That could help you for your future deployments. E.g. LocalConfiguration_1.2.3.yaml -> Since 7.0 you don't have to provide the full version number. You can omit the patch version (last number: LocalConfiguration_1.2.yaml) or the patch and minor version (last two numbers: LocalConfiguration_1.yaml). +> Since 7.0 you don't have to provide the full version number. You can omit the patch version (last number: +> LocalConfiguration_1.2.yaml) or the patch and minor version (last two numbers: LocalConfiguration_1.yaml). ## Configuration (provided by the Configuration Providers) is merged recursively -The configuration arrays provided by the available Configuration Providers are generally merged recursively following the following rules: +The configuration arrays provided by the available Configuration Providers are generally merged recursively following +the following rules: * The value of items having an identical ALPHANUMERIC key will be REPLACED * The value of items having an identical NUMERIC key will be ADDED -* Setting a configuration value to "[__UNSET](#unset)" will remove this configuration from the resulting configuration array +* Setting a configuration value to "[__UNSET](#unset)" will remove this configuration from the resulting configuration + array ### Special treatment of "definition" configuration keys -As of in2publish_core 7.1 every configuration key named "definition" is (compared to the rules noted above) treated specially: +As of in2publish_core 7.1 every configuration key named "definition" is (compared to the rules noted above) treated +specially: * The value of items having an identical NUMERIC key will be REPLACED @@ -65,7 +75,8 @@ adapter.transmission = ssh * disableUserConfig: Disables the UserTsProvider. If checked no UserTS will be merged in the in2publish_core configuration. * adapter.remote & adapter.transmission: - Adapter identifier of the implementation. in2publish_core comes with ssh as default. Other packages like the HTTP-Adapter (in2publish_http) are available from in2code. + Adapter identifier of the implementation. in2publish_core comes with ssh as default. Other packages like the + HTTP-Adapter (in2publish_http) are available from in2code. ## Using environment variables (since 9.2.0) @@ -93,7 +104,8 @@ Read more about dynamic configuration provider in the [Dynamic Configuration Gui Configuration post processing can be required when even custom dynamic configuration provider won't help. A config post processor has the power to alter the complete configuration before it is casted and returned. You should use this feature with care. -Read more about custom configuration post processors in the [Configuration Post Processing Guide](../Guides/ConfigurationPostProcessing.md) +Read more about custom configuration post processors in +the [Configuration Post Processing Guide](../Guides/ConfigurationPostProcessing.md) ## Removing default values @@ -131,7 +143,8 @@ Some configurations can be overwritten by PageTS config and UserTS config (appli PageTS config will always be merged, overruling the configuration of the yaml file. UserTS config can be disabled in the extension configuration. -When the UserTS config is enabled, it will overwrite the configuration after PageTS config was merged, so it always has priority. +When the UserTS config is enabled, it will overwrite the configuration after PageTS config was merged, so it always has +priority. PageTS and UserTs for in2publish starts with **tx_in2publish** followed by the configuration directive to overwrite. @@ -146,25 +159,26 @@ tx_in2publish { } } ``` + --- **Following settings can be overridden by PageTS and UserTS:** - * Debug Settings (debug.*) - * Factory recursion settings (factory.*recursion) - * Publish Files Module folder file limit (factory.fal.folderFileLimit) - * File Preview Domain (Useful in PageTS) (filePreviewDomainName) - * View a) filter buttons b) breadcrumb c) titleField (view.*) +* Debug Settings (debug.*) +* Factory recursion settings (factory.*recursion) +* Publish Files Module folder file limit (factory.fal.folderFileLimit) +* File Preview Domain (Useful in PageTS) (filePreviewDomainName) +* View a) filter buttons b) breadcrumb c) titleField (view.*) **Following settings are accessed before any page or user is resolved or must not be changed by UserTS/PageTS:** - * Foreign Instance Settings (foreign.*) - * Enabled Modules (module.*) - * SSH Connection (sshConnection.*) - * ignoreFieldsForDifferenceView - * TCA Processors (tca.*) - * Tasks (tasks.*) - * Backup settings (backup.*) - * Factory FAL settings (factory.fal.* except factory.fal.folderFileLimit) +* Foreign Instance Settings (foreign.*) +* Enabled Modules (module.*) +* SSH Connection (sshConnection.*) +* ignoreFieldsForDifferenceView +* TCA Processors (tca.*) +* Tasks (tasks.*) +* Backup settings (backup.*) +* Factory FAL settings (factory.fal.* except factory.fal.folderFileLimit) **Continue with [Testing](4_Testing.md)** diff --git a/Documentation/Installation/4_Testing.md b/Documentation/Installation/4_Testing.md index edb131678..93724d296 100644 --- a/Documentation/Installation/4_Testing.md +++ b/Documentation/Installation/4_Testing.md @@ -2,16 +2,19 @@ ## Testing the installation inside TYPO3 -After your preparation, installation and configuration of in2publish, you should log in to the backend of your Local TYPO3. +After your preparation, installation and configuration of in2publish, you should log in to the backend of your Local +TYPO3. Open the backend module **Publish Tools** and select Tests from the drop down. -You should see a couple of test result containers for the configuration tests of in2publish. Please follow the instructions. +You should see a couple of test result containers for the configuration tests of in2publish. Please follow the +instructions. ![Backend module tests](_img/module_tools_test.png) Hint: -> Please note that the container with **SSH2 Functions** could be red, because you do not have a recent copy of the ssh2 library for PHP. +> Please note that the container with **SSH2 Functions** could be red, because you do not have a recent copy of the ssh2 +> library for PHP. > That means that in2publish cannot set permissions for new files and folders on Foreign. If you are using the Foreign's > webprocess user, you do not have to fear any problems. If you are using a different user, you must keep track of > the permissions by yourself, using ACLs or something like that. diff --git a/Documentation/Introduction.md b/Documentation/Introduction.md index 473851ba9..50f1d7a76 100644 --- a/Documentation/Introduction.md +++ b/Documentation/Introduction.md @@ -45,9 +45,12 @@ for easy, intuitive and daily usage focused on editors' daily business. ## Features * Default - * Minimal configuration, maximum gain. in2publish is based on the lowest common denominator of TYPO3 CMS and its extensions, the TCA (Table Configuration Array). + * Minimal configuration, maximum gain. in2publish is based on the lowest common denominator of TYPO3 CMS and its + extensions, the TCA (Table Configuration Array). * Page based publishing of pages, content elements and other structures - * TCA based relation resolving. Any extension which will be installed should work out-of-the-box, as long as it uses common TCA features. Therefore no additional Configuration is neccessary. Configuration options are still provided, described in the Chapter "Configuration". Userfunc in TCA is currently NOT supported. + * TCA based relation resolving. Any extension which will be installed should work out-of-the-box, as long as it uses + common TCA features. Therefore no additional Configuration is neccessary. Configuration options are still + provided, described in the Chapter "Configuration". Userfunc in TCA is currently NOT supported. * Workflow * Define as many workflow states as you need. @@ -55,7 +58,9 @@ for easy, intuitive and daily usage focused on editors' daily business. * Colors in page tree help to identify pages that are in a workflow. * Security - * Any connection between servers and databases is secured by SSH2. All internal methods to create such a connection are based on Private/Public keys. Password authentication is not supported intentionally, but the Private Key may be encrypted using a password. + * Any connection between servers and databases is secured by SSH2. All internal methods to create such a connection + are based on Private/Public keys. Password authentication is not supported intentionally, but the Private Key may + be encrypted using a password. * Eliminates the need for backend users on the production server. * The *production* server is not able to connect to *stage* server. * The configuration file can be stored outside of the webroot. diff --git a/Documentation/KnownIssues.md b/Documentation/KnownIssues.md index 82fef9330..6a1778bbf 100644 --- a/Documentation/KnownIssues.md +++ b/Documentation/KnownIssues.md @@ -11,12 +11,15 @@ process. Then publish the renamed file (or rename it again). ## TYPO3 v9 Preview & Compare URLs The sites configuration introduced in TYPO3 v9 is not yet fully supported when building URLs for the overview module. -Building frontend links in the backend has always been an annoying task, but with the introduction of the sites config it just went worse. +Building frontend links in the backend has always been an annoying task, but with the introduction of the sites config +it just went worse. ## TYPO3 v9 Publish Overview translated pages -When selecting a page in the page tree the publish overview will show everything as expected, except for translated pages. -In TYPO3 9.0 pages_language_overlay was removed and replaced by pages with a sys_language_uid. This is not yet supported. +When selecting a page in the page tree the publish overview will show everything as expected, except for translated +pages. +In TYPO3 9.0 pages_language_overlay was removed and replaced by pages with a sys_language_uid. This is not yet +supported. ## TYPO3 v9 pages sorting detection partially broken diff --git a/Documentation/Manual/Introduction.md b/Documentation/Manual/Introduction.md index a18260847..097cf9f21 100644 --- a/Documentation/Manual/Introduction.md +++ b/Documentation/Manual/Introduction.md @@ -6,15 +6,19 @@ Hint: ## What is the Content Publisher? -The Content Publisher is a TYPO3 extension which provides a backend module to selectively publish content to another TYPO3 instance. +The Content Publisher is a TYPO3 extension which provides a backend module to selectively publish content to another +TYPO3 instance. ## How to use the content publisher -The core version of in2publish does not integrate into the page or list module, so it won't change anything in the view you are accustomed to. +The core version of in2publish does not integrate into the page or list module, so it won't change anything in the view +you are accustomed to. If you want to publish content you have to open the backend module "Publish Overview". -Select the page from the page tree which you want to publish. The page will be shown on the right side of backend and have a highlighting color based on the current state of the record. +Select the page from the page tree which you want to publish. The page will be shown on the right side of backend and +have a highlighting color based on the current state of the record. The color codes are as follows: + * Grey: No changes between Local and Foreign * Yellow: One or more properties changed * Green: The page is new on Local. It was not published yet and does not exist on Foreign diff --git a/Documentation/RequirementsAndLimitations.md b/Documentation/RequirementsAndLimitations.md index 3ca69892f..43d9017df 100644 --- a/Documentation/RequirementsAndLimitations.md +++ b/Documentation/RequirementsAndLimitations.md @@ -6,19 +6,24 @@ You will find more detailed information and hints in each section of the documen ## Operating System / OS Software in2publish_core depends on various common system properties and software for faultless operations. -The most basic dependency is the operating system or short "OS". We've built and tested in2publish on various UNIX based OS to ensure it works in most cases. -Because there are so many different OS out there we can't develop and test in2publish_core on each, so there are a few requirements to the OS that ensure in2publish_core will not run into problems in this level. +The most basic dependency is the operating system or short "OS". We've built and tested in2publish on various UNIX based +OS to ensure it works in most cases. +Because there are so many different OS out there we can't develop and test in2publish_core on each, so there are a few +requirements to the OS that ensure in2publish_core will not run into problems in this level. * All requirements from the TYPO3 version you are using (inherited) -* UNIX/Linux based OS like Ubuntu, Debian, Gentoo or even Mac OS (Windows Server or Windows + XAMPP for example is neither tested nor actively supported) +* UNIX/Linux based OS like Ubuntu, Debian, Gentoo or even Mac OS (Windows Server or Windows + XAMPP for example is + neither tested nor actively supported) * SSH2 on Local, directly executable via `ssh` as the webservers user * SSH-Server on Foreign, authentication via public key * Shell on Foreign for the SSH user (`/bin/bash` in `/etc/passwd`) * Persistent SSH port forwarding (if the database on foreign is not directly accessible) * Environment variables CLI: These must be able to set via `export` or directly beforehand a command -* Environment variables Web: These must be set via SetEnv in the .htaccess or virtual host or before any part (e.g. ext_tables or ext_localconf) of in2publish_core is loaded. +* Environment variables Web: These must be set via SetEnv in the .htaccess or virtual host or before any part (e.g. + ext_tables or ext_localconf) of in2publish_core is loaded. -If you don't know if your servers match all of these minimum requirements please ask your hoster or system administrator. +If you don't know if your servers match all of these minimum requirements please ask your hoster or system +administrator. ## Server Software @@ -27,7 +32,8 @@ The 3 main parts for web applications like TYPO3 are the web server software, th They have to match certain criteria to provide an environment suitable for in2publish. * Web server apache >= 2.2 or nginx1 -* PHP (See [composer.json](https://github.com/in2code-de/in2publish_core/blob/master/composer.json) for the currently required PHP version) +* PHP (See [composer.json](https://github.com/in2code-de/in2publish_core/blob/master/composer.json) for the currently + required PHP version) * PHP Extension [ssh2](https://pecl.php.net/package/ssh2) >= 0.11 (recommended >= 0.12) * MySQL >= 5.6 or MariaDB2 >= 10.1 * A current [TYPO3 LTS](https://typo3.org/typo3-cms/roadmap/) version (not ELTS!). @@ -35,36 +41,58 @@ They have to match certain criteria to provide an environment suitable for in2pu ## PHP settings PHP is the most used language for programming web pages and also the language in2publish_core is written in. -Because it's so wide spread and popular there are a lot of configurations and extensions available to match application requirements. +Because it's so wide spread and popular there are a lot of configurations and extensions available to match application +requirements. Notice that all these numbers are dependent on the size of your TYPO3. -If you have hundreds of thousands of pages and content elements you might have to multiply everything by factor of 2 or even 4. +If you have hundreds of thousands of pages and content elements you might have to multiply everything by factor of 2 or +even 4. -For small TYPO3 instances with a couple handful of pages everything should be fine if you meet TYPO3s minimum requirements. -The more pages, content, extensions and relations you have, the higher the requirement of TYPO3 as well as in2publish_core. -In fact in2publish_core resource requirements might outstrip TYPO3s by far, the more rows you have in your database and the more relations you have defined in your TCA. +For small TYPO3 instances with a couple handful of pages everything should be fine if you meet TYPO3s minimum +requirements. +The more pages, content, extensions and relations you have, the higher the requirement of TYPO3 as well as +in2publish_core. +In fact in2publish_core resource requirements might outstrip TYPO3s by far, the more rows you have in your database and +the more relations you have defined in your TCA. It is recommended to at least double the max_execution_time and memory_limit. -If you are using xdebug be sure you set max_nesting_level at least 5 times of the setting `factory.maximumOverallRecursion` +If you are using xdebug be sure you set max_nesting_level at least 5 times of the +setting `factory.maximumOverallRecursion` # Limitations -The overview and publishing process requires a lot more resources than a normal backend or frontend request, because there is so much stuff going on. -Not every difficult or big task can be made faster (or possible) with more RAM, faster disk I/O and better CPUs, resulting in some inevitable limitations. +The overview and publishing process requires a lot more resources than a normal backend or frontend request, because +there is so much stuff going on. +Not every difficult or big task can be made faster (or possible) with more RAM, faster disk I/O and better CPUs, +resulting in some inevitable limitations. Here's a list of currently known limitations, but without claim of completeness: -* Foreign side relations. Bidirectional relations have an owning and a foreign side. in2publish_core can only resolve relations and hence publish relations from the owning side or else it will run into a loop. -* Maximum number of files in a folder: The publish files module can only handle up to 150 files in a single folder. It's recommended to have a maximum of 100 files in a single folder. - * This limit is configurable as of in2publish_core 8.1.0 but should be used with caution. Read the explanation in the example YAML configuration. - * in2publish (Enterprise Edition) offers a feature that will speed up the Publish Files Module. It processes ~100 files per 0.1 second (limitations apply). -* User generated Content: You can have user generated on foreign and editorial content on stage on the same table if properly configured. It's possible to publish editorial contents, but not to retrieve user generated content. -* Multi Head / Multi Target publishing: in2publish-core can not diff against or publish to more than a single target. You can chain instances and publish from A to B and B to C, but not from A to B and C at the same time. -* Moved/Renamed folders can not be detected. The folder on foreign will be marked as deleted, the one on local will be shown marked new. If you delete the folder from foreign all files within will be removed with their parent folder. Publish files in the Publish Files Module from the renamed folder on local to move them. -* Sorting of records: If a record is published from stage to live, the current value of the column "sorting" is published. This can lead to duplicate or different sorting values between stage and live. Background: If the sorting of a record within a page is changed, all sorting values in all affected records might get changed. As we want to publish only a single record of this page, we prevent the publication of all affected records. +* Foreign side relations. Bidirectional relations have an owning and a foreign side. in2publish_core can only resolve + relations and hence publish relations from the owning side or else it will run into a loop. +* Maximum number of files in a folder: The publish files module can only handle up to 150 files in a single folder. It's + recommended to have a maximum of 100 files in a single folder. + * This limit is configurable as of in2publish_core 8.1.0 but should be used with caution. Read the explanation in + the example YAML configuration. + * in2publish (Enterprise Edition) offers a feature that will speed up the Publish Files Module. It processes ~100 + files per 0.1 second (limitations apply). +* User generated Content: You can have user generated on foreign and editorial content on stage on the same table if + properly configured. It's possible to publish editorial contents, but not to retrieve user generated content. +* Multi Head / Multi Target publishing: in2publish-core can not diff against or publish to more than a single target. + You can chain instances and publish from A to B and B to C, but not from A to B and C at the same time. +* Moved/Renamed folders can not be detected. The folder on foreign will be marked as deleted, the one on local will be + shown marked new. If you delete the folder from foreign all files within will be removed with their parent folder. + Publish files in the Publish Files Module from the renamed folder on local to move them. +* Sorting of records: If a record is published from stage to live, the current value of the column "sorting" is + published. This can lead to duplicate or different sorting values between stage and live. Background: If the sorting + of a record within a page is changed, all sorting values in all affected records might get changed. As we want to + publish only a single record of this page, we prevent the publication of all affected records. --- #### Footnotes: -1. We do not actively develop or test on nginx but we have at least 2 reports of in2publish_core running without problems on nginx. -2. If you use MariaDB because of Galera please notice [Galera Known Limitations](https://mariadb.com/kb/en/mariadb/mariadb-galera-cluster-known-limitations/). TYPO3 MM Tables tend to not have PK fields, which will result in inconsistency across your DB bricks. +1. We do not actively develop or test on nginx but we have at least 2 reports of in2publish_core running without + problems on nginx. +2. If you use MariaDB because of Galera please + notice [Galera Known Limitations](https://mariadb.com/kb/en/mariadb/mariadb-galera-cluster-known-limitations/). TYPO3 + MM Tables tend to not have PK fields, which will result in inconsistency across your DB bricks. diff --git a/Documentation/Use/TheSimpleWay/PublishFiles.md b/Documentation/Use/TheSimpleWay/PublishFiles.md index 35cfdebf1..83ebf5a45 100644 --- a/Documentation/Use/TheSimpleWay/PublishFiles.md +++ b/Documentation/Use/TheSimpleWay/PublishFiles.md @@ -1,9 +1,10 @@ # Publish Files Module -Opening the **Publish Files** module allows editors and administrators to see live changes between the stage and the production system. +Opening the **Publish Files** module allows editors and administrators to see live changes between the stage and the +production system. There is a single folder structure that compares folders with files on both servers. -![Module Files details](_img/module_detail_files.png) +![Module Files details](_img/module_detail_files.png) ## Color Coding @@ -15,28 +16,27 @@ There is a single folder structure that compares folders with files on both serv ## Filtering -Use the folder buttons on the bottom right of the module to filter the structure. -That is useful, e.g., if you want to see only files that have changed. +Use the folder buttons on the bottom right of the module to filter the structure. +That is useful, e.g., if you want to see only files that have changed. The settings will be kept in the user session as long as the user is logged in. - ## See Changes Clicking on the **i**-icon opens a preview link for this file. -![Arrow](_img/icon_info.png) +![Arrow](_img/icon_info.png) ## Publish Files with their related records can be published simply by clicking the arrow icon. This triggers the transfer of the files and records to the production system. -![Arrow](_img/icon_arrow.png) +![Arrow](_img/icon_arrow.png) Note: > The arrow icon is only shown if -> +> > * There are changes, and > * The user has the right to publish. diff --git a/Documentation/Use/TheSimpleWay/PublishOverview.md b/Documentation/Use/TheSimpleWay/PublishOverview.md index 778e01f9d..a5a5c61f4 100644 --- a/Documentation/Use/TheSimpleWay/PublishOverview.md +++ b/Documentation/Use/TheSimpleWay/PublishOverview.md @@ -1,9 +1,10 @@ # Publish Overview Module -Opening the **Publish Overview** module allows editors and administrators see live changes between the stage and production system. +Opening the **Publish Overview** module allows editors and administrators see live changes between the stage and +production system. There is a single page tree that compares records on both servers. -![Module Overview details](_img/module_detail_overview.png) +![Module Overview details](_img/module_detail_overview.png) ## Color Coding @@ -53,4 +54,5 @@ Note: Note: -> If there is a relation from one record to another record on another page, it gets also published. E.g. a news record that has a relation to a content record on another page. +> If there is a relation from one record to another record on another page, it gets also published. E.g. a news record +> that has a relation to a content record on another page. diff --git a/Documentation/Use/TheSimpleWay/README.md b/Documentation/Use/TheSimpleWay/README.md index 04b0dbce1..b4ec92af0 100644 --- a/Documentation/Use/TheSimpleWay/README.md +++ b/Documentation/Use/TheSimpleWay/README.md @@ -6,5 +6,5 @@ Just make your changes on the stage system, check the output and if you're fine, Following pages describe how modules can be used from backend users. -* [Publish Overview](PublishOverview.md) -* [Publish Files](PublishFiles.md) +* [Publish Overview](PublishOverview.md) +* [Publish Files](PublishFiles.md) From 7e35cee1f0512c01a80cb415162141cd4e42ef1d Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 3 May 2022 18:06:44 +0200 Subject: [PATCH 50/56] [CODESTYLE] Fix indent and line length issues --- .../Domain/Repository/RunningRequestRepository.php | 8 ++++---- .../Controller/CompareDatabaseToolController.php | 13 ++++++++++--- .../RedirectsSupport/Domain/Model/SysRedirect.php | 1 - .../ShallowRecordFinder.php | 3 ++- .../Tests/Database/TableGarbageCollectorTest.php | 14 +++++++------- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Classes/Domain/Repository/RunningRequestRepository.php b/Classes/Domain/Repository/RunningRequestRepository.php index 46774bfb5..f04862aba 100644 --- a/Classes/Domain/Repository/RunningRequestRepository.php +++ b/Classes/Domain/Repository/RunningRequestRepository.php @@ -75,8 +75,8 @@ public function isPublishingInDifferentRequest($identifier, string $tableName, s if (!isset($this->rtc['content'])) { $query = $this->connection->createQueryBuilder(); $query->select('*') - ->from(self::RUNNING_REQUEST_TABLE_NAME) - ->where($query->expr()->neq('request_token', $query->createNamedParameter($token))); + ->from(self::RUNNING_REQUEST_TABLE_NAME) + ->where($query->expr()->neq('request_token', $query->createNamedParameter($token))); $result = $query->execute(); foreach ($result->fetchAll() as $row) { $this->rtc['content'][$row['table_name']][$row['record_id']] = true; @@ -89,7 +89,7 @@ public function deleteAllByToken(string $token): void { $query = $this->connection->createQueryBuilder(); $query->delete(self::RUNNING_REQUEST_TABLE_NAME) - ->where($query->expr()->eq('request_token', $query->createNamedParameter($token))) - ->execute(); + ->where($query->expr()->eq('request_token', $query->createNamedParameter($token))) + ->execute(); } } diff --git a/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php b/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php index 0522bd98a..85534aeaa 100644 --- a/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php +++ b/Classes/Features/CompareDatabaseTool/Controller/CompareDatabaseToolController.php @@ -92,9 +92,12 @@ public function compareAction(ComparisonRequest $comparisonRequest = null): void foreach ($tables as $table) { $tableIdentifier = $this->localDatabase->quoteIdentifier($table); - $localResult = $this->localDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchColumn(); + $localResult = $this->localDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier") + ->fetchColumn(); + $tableIdentifier = $this->foreignDatabase->quoteIdentifier($table); - $foreignResult = $this->foreignDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier")->fetchColumn(); + $foreignResult = $this->foreignDatabase->executeQuery("SELECT MAX(uid) from $tableIdentifier") + ->fetchColumn(); if (null === $localResult && null === $foreignResult) { continue; @@ -236,7 +239,11 @@ public function transferAction(string $table, int $uid, string $expected): void $foreignResult = $foreignQuery->execute(); if (1 === $foreignResult) { $this->addFlashMessage( - LocalizationUtility::translate('compare_database.transfer.deleted_from_foreign', 'in2publish_core', [$table, $uid]), + LocalizationUtility::translate( + 'compare_database.transfer.deleted_from_foreign', + 'in2publish_core', + [$table, $uid] + ), LocalizationUtility::translate('compare_database.transfer.success', 'in2publish_core') ); } diff --git a/Classes/Features/RedirectsSupport/Domain/Model/SysRedirect.php b/Classes/Features/RedirectsSupport/Domain/Model/SysRedirect.php index 01a5fb186..473e2b65d 100644 --- a/Classes/Features/RedirectsSupport/Domain/Model/SysRedirect.php +++ b/Classes/Features/RedirectsSupport/Domain/Model/SysRedirect.php @@ -31,7 +31,6 @@ use In2code\In2publishCore\Component\RecordHandling\RecordFinder; use In2code\In2publishCore\Domain\Model\RecordInterface; -use In2code\In2publishCore\Domain\Service\Publishing\RunningRequestService; use In2code\In2publishCore\Event\DetermineIfRecordIsPublishing; use In2code\In2publishCore\Service\Configuration\TcaService; use In2code\In2publishCore\Service\Database\RawRecordService; diff --git a/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php b/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php index 486f06192..e6e0b435c 100644 --- a/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php +++ b/Classes/Features/SimplifiedOverviewAndPublishing/ShallowRecordFinder.php @@ -274,7 +274,8 @@ protected function addChildPagesRecursively(array $pageRecords): array if ($language > 0) { $transOrigPointerField = $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'] ?? null; if (null !== $transOrigPointerField) { - $pid = $record->getLocalProperty($transOrigPointerField) ?? $record->getForeignProperty($transOrigPointerField); + $pid = $record->getLocalProperty($transOrigPointerField) + ?? $record->getForeignProperty($transOrigPointerField); } } } diff --git a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php index 52121757f..6a8fc2e9d 100644 --- a/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php +++ b/Classes/Testing/Tests/Database/TableGarbageCollectorTest.php @@ -51,13 +51,13 @@ public function run(): TestResult $query = $localDatabase->createQueryBuilder(); $query->count('*') - ->from('tx_scheduler_task') - ->where( - $query->expr()->like( - 'serialized_task_object', - $query->createNamedParameter('%tx_in2publishcore_running_request%') - ) - ); + ->from('tx_scheduler_task') + ->where( + $query->expr()->like( + 'serialized_task_object', + $query->createNamedParameter('%tx_in2publishcore_running_request%') + ) + ); $statement = $query->execute(); if (0 === $statement->fetchColumn()) { From bd918938a9c350957c0ab27325743a47ba3efeb5 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Fri, 6 May 2022 09:39:03 +0200 Subject: [PATCH 51/56] [BUGFIX] Correctly indent other icons in the changed content area Relevant for Single Record Publishing (Enterprise Feature) --- Resources/Private/Sass/_ModulesGeneral.scss | 1 + Resources/Public/Css/Modules.css | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Private/Sass/_ModulesGeneral.scss b/Resources/Private/Sass/_ModulesGeneral.scss index 1ae968865..3fb5d4a43 100644 --- a/Resources/Private/Sass/_ModulesGeneral.scss +++ b/Resources/Private/Sass/_ModulesGeneral.scss @@ -283,6 +283,7 @@ a.in2publish-notextdecoration { word-break: break-all; } + span.in2publish-link-publish, [class^="in2publish-icon-"], [class*=" in2publish-icon-"] { padding: 0 10px 0 0; diff --git a/Resources/Public/Css/Modules.css b/Resources/Public/Css/Modules.css index 5979f9adc..f437d44c4 100644 --- a/Resources/Public/Css/Modules.css +++ b/Resources/Public/Css/Modules.css @@ -1 +1 @@ -.in2publish-icon-info{position:absolute;top:1px;right:25px}.in2publish-icon-loop-alt4:before{font-size:90px !important;color:#5D9A46;position:absolute;top:25px;left:-45px}.in2publish-icon-loop-alt4.in2publish-warning:before{color:#FFCA4B}.in2publish-icon-loop-alt4.in2publish-connection-error:before{color:#A94442}.in2publish-icon-folder{margin:0 15px !important;position:relative;top:3px}.in2publish-icon-file{margin:0 15px;position:relative;top:3px}.in2publish-link-publish{position:absolute;right:0;top:1px}.in2publish-link-publish:hover{text-decoration:none}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish{right:1px;cursor:not-allowed}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish:before{content:"\e60a"}.in2publish-stagelisting__item--removed .in2publish-link-publish .in2publish-icon-publish:hover{color:#5D9A46}@font-face{font-family:'in2publish';src:url("../Fonts/in2publish.eot?abcdef");src:url("../Fonts/in2publish.eot?#iefixabcdef") format("embedded-opentype"),url("../Fonts/in2publish.woff?abcdef") format("woff"),url("../Fonts/in2publish.ttf?abcdef") format("truetype"),url("../Fonts/in2publish.svg?abcdef#in2publish") format("svg");font-weight:normal;font-style:normal}[class^="in2publish-icon-"]:before,[class*=" in2publish-icon-"]:before,.in2publish-messages--removeable>.typo3-message:before{font-family:'in2publish';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;font-size:20px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-circle-o:before,.in2publish-icon-circle-o:before{content:"\f10c"}.icon-circle:before,.in2publish-icon-circle:before{content:"\f111"}.icon-blocked:before,.in2publish-icon-blocked:before{content:"\e60a"}.icon-x-altx-alt:before,.in2publish-icon-x-altx-alt:before{content:"\e609"}.icon-folder-download:before,.in2publish-icon-folder-download:before,.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e608"}.icon-history:before,.in2publish-icon-history:before{content:"\e603"}.icon-info:before,.in2publish-icon-info:before{content:"\e601"}.icon-loop-alt4:before,.in2publish-icon-loop-alt4:before{content:"\e600"}.icon-folder:before,.in2publish-icon-folder:before{content:"\e92f"}.icon-folder-open:before,.in2publish-icon-folder-open:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e930"}.icon-folder-plus:before,.in2publish-icon-folder-plus:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e931"}.icon-folder-minus:before,.in2publish-icon-folder-minus:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e932"}.icon-eye:before,.in2publish-icon-eye:before{content:"\e9ce"}.icon-arrow-right:before,.in2publish-link-publish .in2publish-icon-publish:before{content:"\ea34"}.icon-file-broken:before,.in2publish-icon-file-delete:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e604"}.icon-file-add:before,.in2publish-icon-file-add:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e605"}.icon-file-settings:before,.in2publish-icon-file-changed:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e606"}.icon-align-justify:before,.in2publish-icon-file:before{content:"\e607"}.icon-clock2:before{content:"\e60b"}.icon-edit:before,.in2publish-icon-edit:before{content:"\e602"}.nav-pills-container{background:white;padding:10px}div.typo3-fullDoc{height:auto}.in2publish-hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.in2publish-clearfix{zoom:1}.in2publish-clearfix:after{clear:both}.in2publish-clearfix:before,.in2publish-clearfix:after{content:"";display:table}.in2publish-icon-small:before,.in2publish-icon-history:before,.in2publish-icon-info:before,.in2publish-icon-eye:before,.in2publish-icon-edit:before,.in2publish-link-publish .in2publish-icon-publish:before{font-size:16px}.in2publish-unstyledlist{margin:0;padding:0;list-style-type:none}[data-action]{cursor:pointer}.in2publish-inline-block{display:inline-block}.in2publish-backend{font-size:15px;color:#fff}.in2publish-backend h1,.in2publish-backend h2,.in2publish-backend h3,.in2publish-backend h4,.in2publish-backend legend{color:#fff}.in2publish-backend select{color:#444}#typo3-docheader .in2publish-backend-select.module-docheader-bar{overflow:initial}.in2publish-backend *,.in2publish-backend *:before,.in2publish-backend *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.in2publish-backend ul{margin:0;padding:0}.in2publish-module>section{margin:15px 0}.in2publish-module>section>h3{margin-bottom:10px}.in2publish-module{background:#585858}legend{display:block;width:100%;padding:0;margin-bottom:18px;font-size:inherit;line-height:inherit;color:currentColor;border-style:none}label{font-weight:normal}a.in2publish-notextdecoration{text-decoration:none}.in2publish-main{margin-top:40px;overflow:hidden}.in2publish-container{overflow:hidden;margin:0 0 30px}.in2publish-container-50{position:relative;width:50%;float:left;text-align:center}.in2publish-container-50 img{width:90px;height:auto}.in2publish-stagelisting__item__column{background-color:#666;width:50%;float:left;height:30px;line-height:30px;position:relative;top:0;left:0}.in2publish-stagelisting__item__column a{color:#fff}.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column{background-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column{background-color:#A94442}.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column{background-color:#000}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column{background-color:#FFCA4B;color:#585858}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column a,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column a{color:#585858}.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column{background-color:#425ea1}.in2publish-list-level--1 .in2publish-icon-info{right:37px}.in2publish-list-level--1 .in2publish-link-publish{right:12px}.in2publish-list-level--1 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:27px}.in2publish-list-level--2 .in2publish-icon-info{right:49px}.in2publish-list-level--2 .in2publish-link-publish{right:24px}.in2publish-list-level--2 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:39px}.in2publish-list-level--3 .in2publish-icon-info{right:61px}.in2publish-list-level--3 .in2publish-link-publish{right:36px}.in2publish-list-level--3 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:51px}.in2publish-list-level--4 .in2publish-icon-info{right:73px}.in2publish-list-level--4 .in2publish-link-publish{right:48px}.in2publish-list-level--4 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:63px}.in2publish-list-level--5 .in2publish-icon-info{right:85px}.in2publish-list-level--5 .in2publish-link-publish{right:60px}.in2publish-list-level--5 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:75px}.in2publish-backend .in2publish-list-level{margin:0 0 0 25px}.in2publish-backend .in2publish-list-level>li{border-top:1px solid #585858}.in2publish-stagelisting__dropdown{display:none;overflow:hidden;background-color:#DBDBDB;color:#585858;border:10px solid #666}.in2publish-stagelisting__dropdown a{color:currentColor}.in2publish-stagelisting__dropdown h3{background-color:#585858;font-weight:normal;font-size:1em;padding:0 15px;margin-top:0}.in2publish-stagelisting__dropdown h4{background-color:#666;font-style:italic;padding:3px 15px}.in2publish-stagelisting__dropdown li{list-style-type:none;padding:0 0 0 15px;word-break:break-all}.in2publish-stagelisting__dropdown [class^="in2publish-icon-"],.in2publish-stagelisting__dropdown [class*=" in2publish-icon-"]{padding:0 10px 0 0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown{border-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown{border-color:#A94442}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown{border-color:#FFCA4B}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown{border-color:#425ea1}.in2publish-stagelisting__dropdown--open{margin-bottom:10px}.in2publish-stagelisting__dropdown__item{width:50%;float:left;line-height:30px;padding:0}.in2publish-stagelisting__dropdown__item--full{width:100%}.in2publish-stagelisting__dropdown__item h3{line-height:30px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list>li{border-style:none;position:relative}.in2publish-stagelisting__dropdown__actions{padding:0 15px;background-color:#A0A0A0;color:#fff}.in2publish-stagelisting__dropdown__actions>a{margin-right:20px}.in2publish-stagelisting__dropdown__actions>a:last-child{margin-right:0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown__actions{background-color:#5D9A46}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown__actions{background-color:#C15955}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown__actions{background-color:#FFDB88;color:currentColor}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown__actions{background-color:#557AD1;color:#fff}.in2publish-stagelisting__dropdown__page{background-color:#fff}.in2publish-backend .in2publish-related__title{font-style:normal;line-height:30px;padding:0 15px;margin:0;background-color:#FFDB88;color:#444}.in2publish-backend .in2publish-related__list{margin:12px 0 15px}.in2publish-backend .in2publish-related__list li{font-size:14px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list{margin-bottom:12px}.in2publish-footer{margin:20px 0;color:#A0A0A0;font-size:80%}.in2publish-footer .in2publish-logo{float:right;width:160px;height:48px}.in2publish-functions-bar{background-color:#666;margin:20px 0;text-align:center;position:relative;padding:15px;min-height:73px}.in2publish-functions-bar__filter{position:absolute;right:20px;top:22px}.in2publish-functions-bar__filter i:before{font-size:30px}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link{display:inline-block;margin:0 0 0 10px;color:#fff}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link:hover{text-decoration:none}.in2publish-functions-bar__filter .in2publish-functions-bar--active{border-bottom:2px solid #fff}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-changed{border-color:#FFCA4B}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-added{border-color:#5D9A46}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-deleted{border-color:#A94442}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-moved{border-color:#557AD1}.in2publish-preloader{background-color:#585858;height:100%;position:fixed;z-index:100000;text-align:center;opacity:0.9;top:0;left:0;right:0;bottom:0}.in2publish-preloader--hidden{display:none}.in2publish-preloader--spinner{position:relative;top:30%;margin:100px auto;width:50px;height:30px;text-align:center;font-size:10px}.in2publish-preloader--spinner>div{background-color:#fff;height:100%;width:6px;display:inline-block;-webkit-animation:stretchdelay 1.2s infinite ease-in-out;animation:stretchdelay 1.2s infinite ease-in-out}.in2publish-preloader--spinner .rect2{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.in2publish-preloader--spinner .rect3{-webkit-animation-delay:-1.0s;animation-delay:-1.0s}.in2publish-preloader--spinner .rect4{-webkit-animation-delay:-0.9s;animation-delay:-0.9s}.in2publish-preloader--spinner .rect5{-webkit-animation-delay:-0.8s;animation-delay:-0.8s}div#typo3-docbody.stopScrolling{transform:none}@-webkit-keyframes stretchdelay{0%, 40%, 100%{-webkit-transform:scaleY(0.4)}20%{-webkit-transform:scaleY(1)}}@keyframes stretchdelay{0%, 40%, 100%{transform:scaleY(0.4);-webkit-transform:scaleY(0.4)}20%{transform:scaleY(1);-webkit-transform:scaleY(1)}}.in2publish-removevalue:before{right:4px;bottom:4px} +.in2publish-icon-info{position:absolute;top:1px;right:25px}.in2publish-icon-loop-alt4:before{font-size:90px !important;color:#5D9A46;position:absolute;top:25px;left:-45px}.in2publish-icon-loop-alt4.in2publish-warning:before{color:#FFCA4B}.in2publish-icon-loop-alt4.in2publish-connection-error:before{color:#A94442}.in2publish-icon-folder{margin:0 15px !important;position:relative;top:3px}.in2publish-icon-file{margin:0 15px;position:relative;top:3px}.in2publish-link-publish{position:absolute;right:0;top:1px}.in2publish-link-publish:hover{text-decoration:none}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish{right:1px;cursor:not-allowed}.in2publish-stagelisting__item__publish--blocked .in2publish-link-publish .in2publish-icon-publish:before{content:"\e60a"}.in2publish-stagelisting__item--removed .in2publish-link-publish .in2publish-icon-publish:hover{color:#5D9A46}@font-face{font-family:'in2publish';src:url("../Fonts/in2publish.eot?abcdef");src:url("../Fonts/in2publish.eot?#iefixabcdef") format("embedded-opentype"),url("../Fonts/in2publish.woff?abcdef") format("woff"),url("../Fonts/in2publish.ttf?abcdef") format("truetype"),url("../Fonts/in2publish.svg?abcdef#in2publish") format("svg");font-weight:normal;font-style:normal}[class^="in2publish-icon-"]:before,[class*=" in2publish-icon-"]:before,.in2publish-messages--removeable>.typo3-message:before{font-family:'in2publish';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;font-size:20px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-circle-o:before,.in2publish-icon-circle-o:before{content:"\f10c"}.icon-circle:before,.in2publish-icon-circle:before{content:"\f111"}.icon-blocked:before,.in2publish-icon-blocked:before{content:"\e60a"}.icon-x-altx-alt:before,.in2publish-icon-x-altx-alt:before{content:"\e609"}.icon-folder-download:before,.in2publish-icon-folder-download:before,.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e608"}.icon-history:before,.in2publish-icon-history:before{content:"\e603"}.icon-info:before,.in2publish-icon-info:before{content:"\e601"}.icon-loop-alt4:before,.in2publish-icon-loop-alt4:before{content:"\e600"}.icon-folder:before,.in2publish-icon-folder:before{content:"\e92f"}.icon-folder-open:before,.in2publish-icon-folder-open:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e930"}.icon-folder-plus:before,.in2publish-icon-folder-plus:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e931"}.icon-folder-minus:before,.in2publish-icon-folder-minus:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-folder:before{content:"\e932"}.icon-eye:before,.in2publish-icon-eye:before{content:"\e9ce"}.icon-arrow-right:before,.in2publish-link-publish .in2publish-icon-publish:before{content:"\ea34"}.icon-file-broken:before,.in2publish-icon-file-delete:before,.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-folder:before,.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e604"}.icon-file-add:before,.in2publish-icon-file-add:before,.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e605"}.icon-file-settings:before,.in2publish-icon-file-changed:before,.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column .in2publish-icon-file:before,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column .in2publish-icon-file:before{content:"\e606"}.icon-align-justify:before,.in2publish-icon-file:before{content:"\e607"}.icon-clock2:before{content:"\e60b"}.icon-edit:before,.in2publish-icon-edit:before{content:"\e602"}.nav-pills-container{background:white;padding:10px}div.typo3-fullDoc{height:auto}.in2publish-hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.in2publish-clearfix{zoom:1}.in2publish-clearfix:after{clear:both}.in2publish-clearfix:before,.in2publish-clearfix:after{content:"";display:table}.in2publish-icon-small:before,.in2publish-icon-history:before,.in2publish-icon-info:before,.in2publish-icon-eye:before,.in2publish-icon-edit:before,.in2publish-link-publish .in2publish-icon-publish:before{font-size:16px}.in2publish-unstyledlist{margin:0;padding:0;list-style-type:none}[data-action]{cursor:pointer}.in2publish-inline-block{display:inline-block}.in2publish-backend{font-size:15px;color:#fff}.in2publish-backend h1,.in2publish-backend h2,.in2publish-backend h3,.in2publish-backend h4,.in2publish-backend legend{color:#fff}.in2publish-backend select{color:#444}#typo3-docheader .in2publish-backend-select.module-docheader-bar{overflow:initial}.in2publish-backend *,.in2publish-backend *:before,.in2publish-backend *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.in2publish-backend ul{margin:0;padding:0}.in2publish-module>section{margin:15px 0}.in2publish-module>section>h3{margin-bottom:10px}.in2publish-module{background:#585858}legend{display:block;width:100%;padding:0;margin-bottom:18px;font-size:inherit;line-height:inherit;color:currentColor;border-style:none}label{font-weight:normal}a.in2publish-notextdecoration{text-decoration:none}.in2publish-main{margin-top:40px;overflow:hidden}.in2publish-container{overflow:hidden;margin:0 0 30px}.in2publish-container-50{position:relative;width:50%;float:left;text-align:center}.in2publish-container-50 img{width:90px;height:auto}.in2publish-stagelisting__item__column{background-color:#666;width:50%;float:left;height:30px;line-height:30px;position:relative;top:0;left:0}.in2publish-stagelisting__item__column a{color:#fff}.in2publish-stagelisting__item--added .in2publish-stagelisting__item__column{background-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__item__column{background-color:#A94442}.in2publish-stagelisting__item--removed .in2publish-stagelisting__item__column{background-color:#000}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column{background-color:#FFCA4B;color:#585858}.in2publish-stagelisting__item--moved-and-changed .in2publish-stagelisting__item__column a,.in2publish-stagelisting__item--changed .in2publish-stagelisting__item__column a{color:#585858}.in2publish-stagelisting__item--moved .in2publish-stagelisting__item__column{background-color:#425ea1}.in2publish-list-level--1 .in2publish-icon-info{right:37px}.in2publish-list-level--1 .in2publish-link-publish{right:12px}.in2publish-list-level--1 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:27px}.in2publish-list-level--2 .in2publish-icon-info{right:49px}.in2publish-list-level--2 .in2publish-link-publish{right:24px}.in2publish-list-level--2 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:39px}.in2publish-list-level--3 .in2publish-icon-info{right:61px}.in2publish-list-level--3 .in2publish-link-publish{right:36px}.in2publish-list-level--3 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:51px}.in2publish-list-level--4 .in2publish-icon-info{right:73px}.in2publish-list-level--4 .in2publish-link-publish{right:48px}.in2publish-list-level--4 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:63px}.in2publish-list-level--5 .in2publish-icon-info{right:85px}.in2publish-list-level--5 .in2publish-link-publish{right:60px}.in2publish-list-level--5 .in2publish-stagelisting__item__column--right .in2publish-icon-folder{margin-left:75px}.in2publish-backend .in2publish-list-level{margin:0 0 0 25px}.in2publish-backend .in2publish-list-level>li{border-top:1px solid #585858}.in2publish-stagelisting__dropdown{display:none;overflow:hidden;background-color:#DBDBDB;color:#585858;border:10px solid #666}.in2publish-stagelisting__dropdown a{color:currentColor}.in2publish-stagelisting__dropdown h3{background-color:#585858;font-weight:normal;font-size:1em;padding:0 15px;margin-top:0}.in2publish-stagelisting__dropdown h4{background-color:#666;font-style:italic;padding:3px 15px}.in2publish-stagelisting__dropdown li{list-style-type:none;padding:0 0 0 15px;word-break:break-all}.in2publish-stagelisting__dropdown span.in2publish-link-publish,.in2publish-stagelisting__dropdown [class^="in2publish-icon-"],.in2publish-stagelisting__dropdown [class*=" in2publish-icon-"]{padding:0 10px 0 0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown{border-color:#3B7826}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown{border-color:#A94442}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown{border-color:#FFCA4B}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown{border-color:#425ea1}.in2publish-stagelisting__dropdown--open{margin-bottom:10px}.in2publish-stagelisting__dropdown__item{width:50%;float:left;line-height:30px;padding:0}.in2publish-stagelisting__dropdown__item--full{width:100%}.in2publish-stagelisting__dropdown__item h3{line-height:30px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list>li{border-style:none;position:relative}.in2publish-stagelisting__dropdown__actions{padding:0 15px;background-color:#A0A0A0;color:#fff}.in2publish-stagelisting__dropdown__actions>a{margin-right:20px}.in2publish-stagelisting__dropdown__actions>a:last-child{margin-right:0}.in2publish-stagelisting__item--added .in2publish-stagelisting__dropdown__actions{background-color:#5D9A46}.in2publish-stagelisting__item--deleted .in2publish-stagelisting__dropdown__actions{background-color:#C15955}.in2publish-stagelisting__item--changed .in2publish-stagelisting__dropdown__actions{background-color:#FFDB88;color:currentColor}.in2publish-stagelisting__item--moved .in2publish-stagelisting__dropdown__actions{background-color:#557AD1;color:#fff}.in2publish-stagelisting__dropdown__page{background-color:#fff}.in2publish-backend .in2publish-related__title{font-style:normal;line-height:30px;padding:0 15px;margin:0;background-color:#FFDB88;color:#444}.in2publish-backend .in2publish-related__list{margin:12px 0 15px}.in2publish-backend .in2publish-related__list li{font-size:14px}.in2publish-backend .in2publish-stagelisting__dropdown__item__list{margin-bottom:12px}.in2publish-footer{margin:20px 0;color:#A0A0A0;font-size:80%}.in2publish-footer .in2publish-logo{float:right;width:160px;height:48px}.in2publish-functions-bar{background-color:#666;margin:20px 0;text-align:center;position:relative;padding:15px;min-height:73px}.in2publish-functions-bar__filter{position:absolute;right:20px;top:22px}.in2publish-functions-bar__filter i:before{font-size:30px}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link{display:inline-block;margin:0 0 0 10px;color:#fff}.in2publish-functions-bar__filter .in2publish-functions-bar__filter__link:hover{text-decoration:none}.in2publish-functions-bar__filter .in2publish-functions-bar--active{border-bottom:2px solid #fff}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-changed{border-color:#FFCA4B}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-added{border-color:#5D9A46}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-deleted{border-color:#A94442}.in2publish-functions-bar__filter .in2publish-functions-bar--active.in2publish-icon-status-moved{border-color:#557AD1}.in2publish-preloader{background-color:#585858;height:100%;position:fixed;z-index:100000;text-align:center;opacity:0.9;top:0;left:0;right:0;bottom:0}.in2publish-preloader--hidden{display:none}.in2publish-preloader--spinner{position:relative;top:30%;margin:100px auto;width:50px;height:30px;text-align:center;font-size:10px}.in2publish-preloader--spinner>div{background-color:#fff;height:100%;width:6px;display:inline-block;-webkit-animation:stretchdelay 1.2s infinite ease-in-out;animation:stretchdelay 1.2s infinite ease-in-out}.in2publish-preloader--spinner .rect2{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.in2publish-preloader--spinner .rect3{-webkit-animation-delay:-1.0s;animation-delay:-1.0s}.in2publish-preloader--spinner .rect4{-webkit-animation-delay:-0.9s;animation-delay:-0.9s}.in2publish-preloader--spinner .rect5{-webkit-animation-delay:-0.8s;animation-delay:-0.8s}div#typo3-docbody.stopScrolling{transform:none}@-webkit-keyframes stretchdelay{0%, 40%, 100%{-webkit-transform:scaleY(0.4)}20%{-webkit-transform:scaleY(1)}}@keyframes stretchdelay{0%, 40%, 100%{transform:scaleY(0.4);-webkit-transform:scaleY(0.4)}20%{transform:scaleY(1);-webkit-transform:scaleY(1)}}.in2publish-removevalue:before{right:4px;bottom:4px} From a2c2ed10505d77989464cbddb47c8c9380484e99 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Fri, 6 May 2022 12:26:04 +0200 Subject: [PATCH 52/56] [META] Set the EM conf version number to 10.2.3 --- ext_emconf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext_emconf.php b/ext_emconf.php index 7e10340e6..87b7cfb33 100755 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -9,7 +9,7 @@ 'title' => 'in2publish Core', 'description' => 'Content publishing extension to connect stage and production server', 'category' => 'plugin', - 'version' => '10.2.2', + 'version' => '10.2.3', 'state' => 'stable', 'uploadfolder' => 0, 'createDirs' => '', From fa61b50bdc0b25c2eb20cc20897b35bb2a77fb82 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Fri, 6 May 2022 12:26:50 +0200 Subject: [PATCH 53/56] [DOCS] Update changelog --- CHANGELOG.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecc2c82af..f797363c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,53 @@ # In2publish Core Change Log +10.2.3: + +- [META] Set the EM conf version number to 10.2.3 +- [BUGFIX] Correctly indent other icons in the changed content area +- [CODESTYLE] Fix indent and line length issues +- [DOCS] Add missing Event descriptions, reformat all files +- [CODESTYLE] Fix all CS issues in the Tests folder +- [BUGFIX] Add explanation to the failing TableGarbageCollectorTest result +- [CLEANUP] Remove unnecessary string concatenation from BackendUtilityTest +- [REFACTOR] Replace classes for constant access with the class that defines the constant +- [COMMENT] Add copyright blocks to new RunningRequest classes +- [BUGFIX] Deny publishing of a record that is being published, show the process in the View +- [BUGFIX] Mark all records as being published when bulk-publishing +- [BUGFIX] Write all records recursively to the running requests table +- [BUGFIX] Ensure all links in the publish overview mod in yellow rows are black +- [BUGFIX] Use a static property, because ViewHelper Singletons don't work +- [BUGFIX] Only check for publishing processes running in other processes +- [BUGFIX] Remove condition around garbage collector configuration +- [BUGFIX] Use count instead of select to count scheduler task rowsrows +- [FEATURE] Add RegisterViewHelper to set variables in templates that survive scope popping +- [BUGFIX] Move closing quote to the line it belongs +- [BUGFIX] Show the publish loader if redirects are publishing +- [BUGFIX] Use a random token to identify a request instead of the BE user token +- [BUGFIX] Set Records as not publishable if they are already publishing +- [BUGFIX] Replace publishing finished event with shutdown function +- [BUGFIX] Position the publish link instead of just the icon, show publishing records +- [FEATURE] Add Record::isPublishing to determine if a record is currently being published +- [CODESTYLE] Remove blank lines +- [BUGFIX] Fix label for missing garbage collector task +- [TASK] Add a publish tools test checking the existence of a garbage collector task for table tx_in2publishcore_running_request +- [REFACTOR] Move denial of publishing of running request from record to PublishingRequestIsRunningVoter +- [TASK] Do not show publish button if a request is running for publishing of record +- [BUGFIX] Fallback to the foreign property when identifying files +- [BUGFIX] Support doctrine/dbal < 2.11 again +- [BUGFIX] Replace what used to be fetchOne with fetchColumn +- [BUGFIX] Fix non-existing statement method calls in non-composer mode setups +- [BUGFIX] Fix array keys that are used in PHP 8 when using call_user_func_array +- [BUGFIX] Check if a TCA column MM key is set before accessing it +- [BUGFIX] Respect the actual sortby field from the TCA to detect if records were moved +- [BUGFIX] Skip FlexForm select fields without a foreign table +- [BUGFIX] Check if a key exists in the TCA instead of relying on unset key behavior +- [BUGFIX] Prevent undefined index access in DefaultRecordFinder +- [META] Replace extension/module icons +- [BUGFIX] Always preprend the eventListener for the publishing confirmation +- [BUGFIX] Set start depth to 1 for the SimplifiedOverviewAndPublishing root record +- [BUGFIX] Respect record language when attaching pages to parents +- [RELEASE] Version 10.2.2 with minor bug fixes + 10.2.2: - [META] Set the EM conf version number to 10.2.2 From e5fed6de6acf80490992814cc5fbbdce6c815f9c Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 10 May 2022 11:49:51 +0200 Subject: [PATCH 54/56] [BUGFIX] Modify FAL folder identifier to work with most 3rd party drivers Resolves: https://projekte.in2code.de/issues/50044 --- Classes/Controller/FileController.php | 11 +++++++++-- .../Driver/RemoteFileAbstractionLayerDriver.php | 3 +-- Classes/Domain/Factory/FileIndexFactory.php | 2 +- Classes/Domain/Factory/FolderRecordFactory.php | 1 + .../Service/Publishing/FilePublisherService.php | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Classes/Controller/FileController.php b/Classes/Controller/FileController.php index e05159adc..80052fdab 100755 --- a/Classes/Controller/FileController.php +++ b/Classes/Controller/FileController.php @@ -51,9 +51,12 @@ use function count; use function dirname; -use function ltrim; +use function explode; +use function is_string; use function reset; +use function strlen; use function strpos; +use function trim; /** * The FileController is responsible for the "Publish Files" Backend module "m2" @@ -133,7 +136,7 @@ public function publishFileAction(int $uid, string $identifier, int $storage): v [$identifier] = GeneralUtility::trimExplode(',', $identifier); } - $record = $this->tryToGetFolderInstance($storage . ':/' . ltrim(dirname($identifier), '/')); + $record = $this->tryToGetFolderInstance($storage . ':' . dirname($identifier)); if (null !== $record) { $relatedRecords = $record->getRelatedRecordByTableAndProperty('sys_file', 'identifier', $identifier); @@ -186,6 +189,10 @@ public function toggleFilterStatusAndRedirectToIndexAction(string $filter): void */ protected function tryToGetFolderInstance(?string $identifier): ?RecordInterface { + if (is_string($identifier) && strpos($identifier, ':') < strlen($identifier)) { + [$storage, $name] = explode(':', $identifier); + $identifier = $storage . ':' . trim($name, '/') . '/'; + } if (false === $this->configContainer->get('factory.fal.reserveSysFileUids')) { try { $record = GeneralUtility::makeInstance(IndexingFolderRecordFactory::class)->makeInstance($identifier); diff --git a/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php b/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php index 185166f1f..30465e16b 100644 --- a/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php +++ b/Classes/Domain/Driver/RemoteFileAbstractionLayerDriver.php @@ -53,6 +53,7 @@ use function array_combine; use function array_keys; use function is_array; +use function ltrim; use function sprintf; /** @@ -497,8 +498,6 @@ public function getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtr public function getFolderInfoByIdentifier($folderIdentifier): array { $callback = function () use ($folderIdentifier) { - $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier); - if (!$this->folderExists($folderIdentifier)) { throw new FolderDoesNotExistException( 'Folder "' . $folderIdentifier . '" does not exist.', diff --git a/Classes/Domain/Factory/FileIndexFactory.php b/Classes/Domain/Factory/FileIndexFactory.php index e8a9313dd..13c3828c0 100644 --- a/Classes/Domain/Factory/FileIndexFactory.php +++ b/Classes/Domain/Factory/FileIndexFactory.php @@ -247,7 +247,7 @@ public function getFileIndexArray(string $identifier, string $side, int $uid = 0 */ protected function determineFileType(array $fileInfo): int { - [$fileType] = explode('/', $fileInfo['mime_type']); + [$fileType] = explode('/', $fileInfo['mime_type'] ?? ''); switch (strtolower($fileType)) { case 'text': $type = AbstractFile::FILETYPE_TEXT; diff --git a/Classes/Domain/Factory/FolderRecordFactory.php b/Classes/Domain/Factory/FolderRecordFactory.php index 65eda595e..710bf8fa6 100644 --- a/Classes/Domain/Factory/FolderRecordFactory.php +++ b/Classes/Domain/Factory/FolderRecordFactory.php @@ -492,6 +492,7 @@ protected function getFolderInfoByIdentifier(DriverInterface $driver, string $id { if ($driver->folderExists($identifier)) { $info = $driver->getFolderInfoByIdentifier($identifier); + $info['identifier'] = trim($info['identifier'], '/') . '/'; $info['uid'] = sprintf('%d:%s', $info['storage'], $info['identifier']); } else { $info = []; diff --git a/Classes/Domain/Service/Publishing/FilePublisherService.php b/Classes/Domain/Service/Publishing/FilePublisherService.php index 73beab158..e7dcbf786 100644 --- a/Classes/Domain/Service/Publishing/FilePublisherService.php +++ b/Classes/Domain/Service/Publishing/FilePublisherService.php @@ -85,7 +85,7 @@ public function addFileToForeign(int $storage, string $fileIdentifier): bool return false; } - $folderIdentifier = dirname($fileIdentifier); + $folderIdentifier = trim(dirname($fileIdentifier), '/') . '/'; if (!$this->remoteFalDriver->folderExists($folderIdentifier)) { $this->remoteFalDriver->createFolder(basename($folderIdentifier), dirname($folderIdentifier), true); } From 830697bf278a74824559e6464ae19591d5cf30a9 Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 17 May 2022 15:38:45 +0200 Subject: [PATCH 55/56] [META] Set the EM conf version number to 11.0.2 Resolves: https://projekte.in2code.de/issues/50803 --- ext_emconf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext_emconf.php b/ext_emconf.php index b50f3e176..d85a71c59 100755 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -9,7 +9,7 @@ 'title' => 'in2publish Core', 'description' => 'Content publishing extension to connect stage and production server', 'category' => 'plugin', - 'version' => '11.0.1', + 'version' => '11.0.2', 'state' => 'stable', 'clearCacheOnLoad' => true, 'author' => 'Alex Kellner, Oliver Eglseder, Thomas Scheibitz, Stefan Busemann', From ed0c1ffd0364f92069a610aca960e73b4c01649c Mon Sep 17 00:00:00 2001 From: Oliver Eglseder Date: Tue, 17 May 2022 15:39:01 +0200 Subject: [PATCH 56/56] [DOCS] Update changelog --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d58eb1e3..4c2c21df7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # In2publish Core Change Log +11.0.2: + +- **Everything included in the 10.2.3 release** +- [BUGFIX] Modify FAL folder identifier to work with most 3rd party drivers +- [BUGFIX] Replace deprecated FILTER_SANITIZE_STRING option from filter_var with htmlspecialchars +- [BUGFIX] Hide publish file/redirect button if the record is being published +- [BUGFIX] Resolve doctrine/dbal deprecations +- [BUGFIX] Implement missing replacement for SITE markers in TCA +- [REFACTOR] Inject a DB connection in ReplaceMarkersService to get rid of static calls +- [TASK] Apply review feedback +- [BUGFIX] Add missing SiteFinder use statement +- [TASK] Also replace SITE: markers in FlexForms +- [TASK] Add test for replaceSiteMarker functionality +- [BUGFIX] Adjust test cases for ReplaceMarkersService to match new constructor +- [FEATURE] Implement replacement of SITE: markers in TCA +- [RELEASE] Version 11.0.1 with minor bug fixes + 11.0.1: - [META] Set the EM conf version number to 11.0.1