Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Classes/Form/FormDataProvider/TcaColPosItems.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,21 @@ public function addData(array $result)
}
}

$cType = $record['CType'][0];
if (!empty($columnConfiguration['maxitemsByCType.'][$cType])
&& $columnConfiguration['maxitemsByCType.'][$cType] <= $this->contentRepository->countColPosByRecordType($record, $cType)
) {
$isCurrentColPos = $colPos === (int)$result['databaseRow']['colPos'][0];
if ($isCurrentColPos && !$this->contentRepository->isRecordInColPos($record)) {
throw new AccessDeniedColPosException(
'Maximum number of allowed content elements by CType "' . $cType . '" (' . $columnConfiguration['maxitemsByCType.'][$cType] . ') reached.',
1749209557
);
} elseif (!$isCurrentColPos) {
unset($result['processedTca']['columns']['colPos']['config']['items'][$key]);
}
}

if (!empty($columnConfiguration['maxitems'])
&& $columnConfiguration['maxitems'] <= $this->contentRepository->countColPosByRecord($record)
) {
Expand Down
18 changes: 18 additions & 0 deletions Classes/Hooks/AbstractDataHandlerHook.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,22 @@ protected function isRecordAllowedByItemsCount(array $columnConfiguration, array

return (int)$columnConfiguration['maxitems'] >= $this->contentRepository->addRecordToColPos($record);
}

/**
* @param array $columnConfiguration
* @param array $record
* @return bool
*/
protected function isRecordAllowedByItemsCountAndCType(array $columnConfiguration, array $record)
{
$cType = $record['CType'];
if (!empty($columnConfiguration['maxitemsByCType.'])) {
$this->contentRepository->addRecordToColPos($record);
if ($this->contentRepository->countColPosByRecordType($record, $cType) >= (int)$columnConfiguration['maxitemsByCType.']) {
return false;
}
}

return true;
}
}
24 changes: 24 additions & 0 deletions Classes/Hooks/DatamapDataHandlerHook.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ public function processDatamap_beforeStart(DataHandler $dataHandler)
);
}

if (!$this->isRecordAllowedByItemsCountAndCType($columnConfiguration, $incomingFieldArray)) {
// DataHandler copies a record by first add a new content element (in the old colPos) and then adjust
// the colPos information to the target colPos. This means we have to allow this element to be added
// even if the maxitems is reached already. The copy command was checked in CmdmapDataHandlerHook.
if (empty($dataHandler->cmdmap) && !empty($_POST['CB']['paste'] ?? $_GET['CB']['paste'] ?? null)) {
continue;
}
$cType = $incomingFieldArray['CType'];
unset($dataHandler->datamap['tt_content'][$id]);
$dataHandler->log(
'tt_content',
$id,
1,
$pageId,
1,
'The record "%s" couldn\'t be saved due to reached maxitemsByCType configuration of %d.',
27,
[
$incomingFieldArray[$GLOBALS['TCA']['tt_content']['ctrl']['label']],
$columnConfiguration['maxitemsByCType.'][$cType],
]
);
}

if (!$this->isRecordAllowedByItemsCount($columnConfiguration, $incomingFieldArray)) {
// DataHandler copies a record by first add a new content element (in the old colPos) and then adjust
// the colPos information to the target colPos. This means we have to allow this element to be added
Expand Down
20 changes: 18 additions & 2 deletions Classes/Repository/ContentRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@ public function countColPosByRecord(array $record): int
return count($this->colPosCount[$identifier]);
}

public function countColPosByRecordType(array $record, string $cType): int
{
$identifier = $this->getIdentifier($record);

if (!isset($this->colPosCount[$identifier])) {
$this->initialize($record);
}

$colPosCountState = $this->colPosCount[$identifier];
$allEntries = $colPosCountState[null];
$countByCType = array_count_values($allEntries);

return $countByCType[$cType] ?? 0;
}

public function addRecordToColPos(array $record): int
{
$identifier = $this->getIdentifier($record);
Expand Down Expand Up @@ -118,7 +133,7 @@ protected function fetchRecordsForColPos(array $record): array
$languageField = $GLOBALS['TCA']['tt_content']['ctrl']['languageField'];
$language = (array)($record[$languageField] ?? 0);

$selectFields = ['uid', 'pid'];
$selectFields = ['uid', 'pid', 'CType'];
if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['versioningWS'])) {
$selectFields[] = 't3ver_state';
}
Expand Down Expand Up @@ -151,7 +166,8 @@ protected function fetchRecordsForColPos(array $record): array
BackendUtility::workspaceOL('tt_content', $row, -99, true);
if (is_array($row) && !VersionState::cast($row['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)) {
$uid = ($row['_ORIG_uid'] ?? 0) ?: $row['uid'];
$rows[$uid] = $uid;
$cType = $row['CType'];
$rows[$uid] = $cType;
}
}

Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,25 @@ columns {
}
```

- To restrict the number of content elements by type use `maxitemsByCType.[type] = [number of elements]`

*Example:*
```
columns {
1 {
name = Column with one textmedia
colPos = 3
colspan = 6
allowed {
CType = textmedia, header
}
maxitemsByCType {
header = 1
}
}
}
```

## Known issues

### TypeError
Expand Down
Loading