Skip to content

Commit d0b7ace

Browse files
committed
[RELEASE] Version 9.3.0 with publish page context menu entry, file edge cache invalidation, and much more
Releases: https://projekte.in2code.de/issues/41730 Releases: #81 Releases: #80 Releases: https://projekte.in2code.de/issues/42172 Releases: https://projekte.in2code.de/issues/33332 Releases: https://projekte.in2code.de/issues/36617 Releases: https://projekte.in2code.de/issues/42436 Releases: https://projekte.in2code.de/issues/36616 Resolves: https://projekte.in2code.de/issues/42863
2 parents 0de05d0 + 5819385 commit d0b7ace

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+858
-79
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
11
# In2publish Core Change Log
22

3+
9.3.0:
4+
5+
- [META] Set the branch alias version number to 9.3.x-dev
6+
- [META] Set the EM conf version number to 9.3.0
7+
- [FEATURE] Add option to treat different levels of deletion differently
8+
- [BUGFIX] Do not retry to search for a site which can not be found
9+
- [BUGFIX] Correctly detect deleted states of records removed from local
10+
- [FEATURE] Display removed records with a black background and X-Icon
11+
- [FEATURE] Add option to treat removal as difference to deletion
12+
- [FEATURE] Clear caches of all related pages when publishing files
13+
- [FEATURE] Add file edge cache invalidator
14+
- [FEATURE] Add publish page option to page tree context menu
15+
- [FEATURE] Add enable config option for feature contextMenuPublishEntry
16+
- [FEATURE] Add translations, document dumb menu entry
17+
- [FEATURE] Ask external voters if a record can be published
18+
- [WIP][FEATURE] Add a context menu action to publish a page
19+
- [DOCS] Add known issue about broken foreign file preview urls
20+
- [BUGFIX] Add missing return type hints in Record/Interface
21+
- [BUGFIX] Hide duplicate sys_file records
22+
- [BUGFIX] Skip the attempt to generate a preview URL for page ID 0
23+
- [TYPO] Fix some typos in FolderRecordFactory developer guide comments
24+
- [REFACTOR] Move TCA record label construction logic to TcaService
25+
- [BUGFIX] Add additionWhere only if it's not empty
26+
- [BUGFIX] Remove error level from performance tests and raise the warning limits
27+
- [BUGFIX] Use DBAL count method to count instead of SQL function name as column
28+
- [BUGFIX] Support sql escape sequence in FlexForm foreign_table_where
29+
- [RELEASE] Version 9.2.0 with env vars, internal_type file_reference and config debug
30+
331
9.2.0:
432

533
- [META] Set the branch alias version number to 9.1.x-dev

Classes/Communication/RemoteProcedureCall/EnvelopeDispatcher.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ protected function folderExists(array $request): array
135135
$files[$fileIdentifier] = [];
136136
$files[$fileIdentifier]['hash'] = $driver->hash($fileIdentifier, 'sha1');
137137
$files[$fileIdentifier]['info'] = $driver->getFileInfoByIdentifier($fileIdentifier);
138+
// getPublicUrl does not work on CLI and non-public storages https://forge.typo3.org/issues/90330
138139
$files[$fileIdentifier]['publicUrl'] = $storage->getPublicUrl($fileObject);
139140
}
140141
}

Classes/Config/Definer/In2publishCoreDefiner.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ public function getLocalDefinition()
192192
->addInteger('maximumOverallRecursion', 8)
193193
->addBoolean('resolvePageRelations', false)
194194
->addBoolean('includeSysFileReference', false)
195+
->addBoolean('treatRemovedAndDeletedAsDifference', false)
195196
->addArray(
196197
'fal',
197198
Builder::start()
@@ -285,6 +286,15 @@ public function getLocalDefinition()
285286
[IterativeTcaProcessorValidator::class]
286287
)
287288
)
289+
->addArray(
290+
'features',
291+
Builder::start()
292+
->addArray(
293+
'contextMenuPublishEntry',
294+
Builder::start()
295+
->addBoolean('enable', false)
296+
)
297+
)
288298
->end();
289299
}
290300

Classes/Controller/FileController.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
use In2code\In2publishCore\Domain\Model\RecordInterface;
3737
use In2code\In2publishCore\Domain\Repository\CommonRepository;
3838
use In2code\In2publishCore\Domain\Service\Publishing\FolderPublisherService;
39+
use In2code\In2publishCore\Utility\DatabaseUtility;
3940
use RuntimeException;
4041
use Throwable;
4142
use TYPO3\CMS\Core\Messaging\AbstractMessage;
@@ -47,6 +48,9 @@
4748
use TYPO3\CMS\Extbase\SignalSlot\Exception\InvalidSlotReturnException;
4849
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
4950

51+
use function array_key_exists;
52+
use function count;
53+
use function in_array;
5054
use function strpos;
5155

5256
/**

Classes/Domain/Factory/FolderRecordFactory.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ protected function initializeDependenciesAndGetFolder($identifier): Folder
130130
// The root level folder is the "real" default and also respects mount points of the current user.
131131
$localFolder = $localStorage->getRootLevelFolder();
132132
} else {
133-
// This is the normal case. The identifier identifies the folder inclusive its storage.
133+
// This is the normal case. The identifier identifies the folder including its storage.
134134
try {
135135
$localFolder = $resourceFactory->getFolderObjectFromCombinedIdentifier($identifier);
136136
} catch (FolderDoesNotExistException $exception) {
@@ -194,6 +194,9 @@ public function makeInstance($identifier): RecordInterface
194194
$properties = ['folder_hash' => $hashedIdentifier, 'storage' => $storageUid];
195195
$files = $this->commonRepository->findByProperties($properties, true, 'sys_file');
196196

197+
// Identify sys_file entries with identical identifiers and add all duplicates as related record.
198+
$files = $this->moveSameSysFileRecordsToRelatedRecords($files);
199+
197200
// FEATURE: mergeSysFileByIdentifier and enableSysFileReferenceUpdate
198201
if (true === $this->configuration['mergeSysFileByIdentifier']) {
199202
$files = $this->mergeSysFileByIdentifier($files);
@@ -551,7 +554,7 @@ protected function getFolderInfoByIdentifier(DriverInterface $driver, $identifie
551554
protected function fixIntersectingIdentifiers(array $diskIdentifiers, array $indexedIdentifiers, array $files)
552555
{
553556
foreach (['local' => 'foreign', 'foreign' => 'local'] as $diskSide => $indexSide) {
554-
// Find intersecting identifiers. These are identifiers only on one disk and teh opposite database.
557+
// Find intersecting identifiers. These are identifiers only on one disk and the opposite database.
555558
$notIndexedIdentifier = array_diff(
556559
$diskIdentifiers[$diskSide],
557560
$indexedIdentifiers[$diskSide],
@@ -877,4 +880,29 @@ protected function convertIdentifiers(DriverInterface $driver, array $identifier
877880
}
878881
return $identifierList;
879882
}
883+
884+
/**
885+
* TYPO3 may create more than one sys_file record for an actual file (or different versions of it).
886+
* Each sys_file record will be shown as an independent record in the publish files module.
887+
* To prevent these duplications, we take every sys_file record which has an identical identifier as any previous
888+
* record and attach that record as a related record, so they will be published as one.
889+
*
890+
* @param RecordInterface[] $files
891+
* @return RecordInterface[]
892+
*/
893+
protected function moveSameSysFileRecordsToRelatedRecords(array $files): array
894+
{
895+
/** @var RecordInterface[] $fileRecords */
896+
$fileRecords = [];
897+
foreach ($files as $idx => $file) {
898+
$localIdentifier = $file->getLocalProperty('identifier');
899+
if (isset($fileRecords[$localIdentifier])) {
900+
$fileRecords[$localIdentifier]->addRelatedRecord($file);
901+
unset($files[$idx]);
902+
} else {
903+
$fileRecords[$localIdentifier] = $file;
904+
}
905+
}
906+
return $files;
907+
}
880908
}

Classes/Domain/Model/Record.php

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,12 @@
3333
use In2code\In2publishCore\Config\ConfigContainer;
3434
use In2code\In2publishCore\Domain\Service\TcaProcessingService;
3535
use In2code\In2publishCore\Service\Configuration\TcaService;
36+
use In2code\In2publishCore\Service\Permission\PermissionService;
3637
use LogicException;
3738
use TYPO3\CMS\Core\Utility\GeneralUtility;
3839

40+
use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
41+
3942
use function array_diff;
4043
use function array_filter;
4144
use function array_key_exists;
@@ -442,7 +445,7 @@ public function setForeignProperties(array $foreignProperties): RecordInterface
442445
* @param string $side
443446
* @param array $properties
444447
*
445-
* @return $this
448+
* @return RecordInterface
446449
*/
447450
public function setPropertiesBySideIdentifier($side, array $properties): RecordInterface
448451
{
@@ -861,7 +864,7 @@ public function getMergedProperty($propertyName)
861864
*
862865
* @return void
863866
*/
864-
public function calculateState()
867+
public function calculateState(): void
865868
{
866869
if ($this->tableName === 'sys_file' && !isset($this->additionalProperties['recordDatabaseState'])) {
867870
if ($this->hasLocalProperty('identifier') && $this->hasForeignProperty('identifier')) {
@@ -1246,4 +1249,27 @@ public function getRecordLanguage(): int
12461249

12471250
return $language;
12481251
}
1252+
1253+
public function isPublishable(): bool
1254+
{
1255+
if (!$this->isChangedRecursive()) {
1256+
return false;
1257+
}
1258+
$permissionService = GeneralUtility::makeInstance(PermissionService::class);
1259+
if (!$permissionService->isUserAllowedToPublish()) {
1260+
return false;
1261+
}
1262+
$signalSlotDispatcher = GeneralUtility::makeInstance(Dispatcher::class);
1263+
$votes = $signalSlotDispatcher->dispatch(
1264+
RecordInterface::class,
1265+
'isPublishable',
1266+
[['yes' => 0, 'no' => 0], $this->tableName, $this->getIdentifier()]
1267+
);
1268+
return $votes[0]['yes'] >= $votes[0]['no'];
1269+
}
1270+
1271+
public function isRemovedFromLocalDatabase(): bool
1272+
{
1273+
return $this->isForeignRecordDeleted() && !$this->isRecordRepresentByProperties($this->localProperties);
1274+
}
12491275
}

Classes/Domain/Model/RecordInterface.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,17 +133,17 @@ public function setForeignProperties(array $foreignProperties): RecordInterface;
133133
/**
134134
* @return RecordInterface
135135
*/
136-
public function setDirtyProperties();
136+
public function setDirtyProperties(): RecordInterface;
137137

138138
/**
139139
* @return mixed
140140
*/
141141
public function getDirtyProperties();
142142

143143
/**
144-
* @return RecordInterface
144+
* @return void
145145
*/
146-
public function calculateState();
146+
public function calculateState(): void;
147147

148148
/**
149149
* @return bool
@@ -158,17 +158,17 @@ public function isLocalRecordDeleted(): bool;
158158
/**
159159
* Returns an identifier unique in the records table.
160160
*
161-
* @return @return int|string
161+
* @return int|string
162162
*/
163163
public function getIdentifier();
164164

165165
/**
166166
* @param string $side
167167
* @param array $properties
168168
*
169-
* @return $this
169+
* @return RecordInterface
170170
*/
171-
public function setPropertiesBySideIdentifier($side, array $properties);
171+
public function setPropertiesBySideIdentifier($side, array $properties): RecordInterface;
172172

173173
/**
174174
* @param string $side
@@ -371,4 +371,8 @@ public function getPageIdentifier(): int;
371371
public function getSuperordinatePageIdentifier(): int;
372372

373373
public function getRecordLanguage(): int;
374+
375+
public function isPublishable(): bool;
376+
377+
public function isRemovedFromLocalDatabase(): bool;
374378
}

Classes/Domain/Repository/BaseRepository.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,10 @@ protected function findPropertiesByProperty(
157157
$query->getRestrictions()->removeAll();
158158
$query->select('*')
159159
->from($tableName)
160-
->where($query->expr()->like($propertyName, $query->createNamedParameter($propertyValue)))
161-
->andWhere($additionalWhere);
160+
->where($query->expr()->like($propertyName, $query->createNamedParameter($propertyValue)));
161+
if (!empty($additionalWhere)) {
162+
$query->andWhere($additionalWhere);
163+
}
162164

163165
if (!empty($groupBy)) {
164166
$query->groupBy($groupBy);
@@ -225,8 +227,10 @@ public function findPropertiesByProperties(
225227
$query = $connection->createQueryBuilder();
226228
$query->getRestrictions()->removeAll();
227229
$query->select('*')
228-
->from($tableName)
229-
->andWhere($additionalWhere);
230+
->from($tableName);
231+
if (!empty($additionalWhere)) {
232+
$query->andWhere($additionalWhere);
233+
}
230234

231235
foreach ($properties as $propertyName => $propertyValue) {
232236
$query->andWhere($query->expr()->like($propertyName, $query->createNamedParameter($propertyValue)));

Classes/Domain/Repository/CommonRepository.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
*/
3232

3333
use Exception;
34+
use In2code\In2publishCore\Config\ConfigContainer;
3435
use In2code\In2publishCore\Domain\Factory\RecordFactory;
3536
use In2code\In2publishCore\Domain\Model\NullRecord;
3637
use In2code\In2publishCore\Domain\Model\RecordInterface;
@@ -46,6 +47,7 @@
4647
use TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidTcaException;
4748
use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
4849
use TYPO3\CMS\Core\Database\Connection;
50+
use TYPO3\CMS\Core\Database\Query\QueryHelper;
4951
use TYPO3\CMS\Core\Resource\ResourceFactory;
5052
use TYPO3\CMS\Core\Service\FlexFormService;
5153
use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -140,6 +142,11 @@ class CommonRepository extends BaseRepository
140142
*/
141143
protected $signalSlotDispatcher;
142144

145+
/**
146+
* @var ConfigContainer
147+
*/
148+
protected $configContainer = null;
149+
143150
/**
144151
* @var Connection
145152
*/
@@ -185,6 +192,7 @@ public function __construct(
185192
$this->resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
186193
$this->taskRepository = GeneralUtility::makeInstance(TaskRepository::class);
187194
$this->signalSlotDispatcher = GeneralUtility::makeInstance(Dispatcher::class);
195+
$this->configContainer = GeneralUtility::makeInstance(ConfigContainer::class);
188196
$this->identifierFieldName = $identifierFieldName ?: $this->identifierFieldName;
189197
$this->localDatabase = $localDatabase;
190198
$this->foreignDatabase = $foreignDatabase;
@@ -1512,11 +1520,9 @@ protected function fetchRelatedRecordsBySelect(
15121520
if (!empty($columnConfiguration['foreign_table_where'])) {
15131521
/** @var ReplaceMarkersService $replaceMarkers */
15141522
$replaceMarkers = GeneralUtility::makeInstance(ReplaceMarkersService::class);
1515-
$whereClause = $replaceMarkers->replaceMarkers(
1516-
$record,
1517-
$columnConfiguration['foreign_table_where'],
1518-
$propertyName
1519-
);
1523+
$foreignTblWhere = $columnConfiguration['foreign_table_where'];
1524+
$foreignTblWhere = QueryHelper::quoteDatabaseIdentifiers($this->localDatabase, $foreignTblWhere);
1525+
$whereClause = $replaceMarkers->replaceMarkers($record, $foreignTblWhere, $propertyName);
15201526
}
15211527

15221528
$uidArray = [];
@@ -1901,6 +1907,9 @@ protected function isIgnoredRecord(array $localProperties, array $foreignPropert
19011907
*/
19021908
protected function isRemovedAndDeletedRecord(array $localProps, array $foreignProps): bool
19031909
{
1910+
if ($this->configContainer->get('factory.treatRemovedAndDeletedAsDifference')) {
1911+
return false;
1912+
}
19041913
return (empty($localProps) && isset($foreignProps['deleted']) && 1 === (int)$foreignProps['deleted'])
19051914
|| (empty($foreignProps) && isset($localProps['deleted']) && 1 === (int)$localProps['deleted']);
19061915
}

Classes/Domain/Service/TableConfiguration/LabelService.php

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
use function array_merge;
3939
use function array_unique;
4040
use function sprintf;
41+
use function trim;
4142

4243
/**
4344
* Class LabelService
@@ -70,27 +71,27 @@ public function __construct()
7071
*
7172
* @return string
7273
*/
73-
public function getLabelField($record, $stagingLevel = 'local'): string
74+
public function getLabelField(RecordInterface $record, $stagingLevel = 'local'): string
7475
{
75-
$tableName = $record->getTableName();
76+
$table = $record->getTableName();
7677

77-
if ($tableName === 'sys_file_reference') {
78+
if ($table === 'sys_file_reference') {
7879
return sprintf(
7980
'%d [%d,%d]',
8081
$record->getPropertyBySideIdentifier($stagingLevel, 'uid'),
8182
$record->getPropertyBySideIdentifier($stagingLevel, 'uid_local'),
8283
$record->getPropertyBySideIdentifier($stagingLevel, 'uid_foreign')
8384
);
8485
}
85-
86-
$fields = $this->getLabelFieldsFromTableConfiguration($tableName);
87-
foreach ($fields as $field) {
88-
$recordProperties = ObjectAccess::getProperty($record, $stagingLevel . 'Properties');
89-
if (!empty($recordProperties[$field])) {
90-
return (string)$recordProperties[$field];
91-
}
86+
$row = ObjectAccess::getProperty($record, $stagingLevel . 'Properties');
87+
if (empty($row)) {
88+
return $this->emptyFieldValue;
89+
}
90+
$label = $this->tcaService->getRecordLabel($row, $table);
91+
if (trim($label) === '') {
92+
$label = $this->emptyFieldValue;
9293
}
93-
return $this->emptyFieldValue;
94+
return $label;
9495
}
9596

9697
/**

0 commit comments

Comments
 (0)