Skip to content

Commit 463809e

Browse files
committed
[FEATURE] Re-definition of Core Page Types
1 parent 5891283 commit 463809e

File tree

11 files changed

+146
-24
lines changed

11 files changed

+146
-24
lines changed

Classes/Definition/ContentType/ContentTypeIcon.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public static function fromArray(array $array): ContentTypeIcon
3333
$self->iconPath = $array['iconPath'] ?? '';
3434
$self->iconProvider = $array['iconProvider'] ?? '';
3535
$self->iconIdentifier = $array['iconIdentifier'] ?? '';
36-
if ($self->iconPath !== '' && $self->iconIdentifier !== '') {
36+
if (($array['initialized'] ?? false) || ($self->iconPath !== '' && $self->iconIdentifier !== '')) {
3737
$self->initialized = true;
3838
}
3939
return $self;
@@ -45,6 +45,7 @@ public function toArray(): array
4545
'iconPath' => $this->iconPath,
4646
'iconProvider' => $this->iconProvider,
4747
'iconIdentifier' => $this->iconIdentifier,
48+
'initialized' => $this->initialized,
4849
];
4950
}
5051
}

Classes/Generator/TcaGenerator.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use TYPO3\CMS\ContentBlocks\Registry\LanguageFileRegistry;
3838
use TYPO3\CMS\ContentBlocks\Schema\SimpleTcaSchemaFactory;
3939
use TYPO3\CMS\ContentBlocks\Service\SystemExtensionAvailability;
40+
use TYPO3\CMS\ContentBlocks\Validation\PageTypeNameValidator;
4041
use TYPO3\CMS\Core\Configuration\Event\BeforeTcaOverridesEvent;
4142
use TYPO3\CMS\Core\Utility\ArrayUtility;
4243
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
@@ -165,7 +166,9 @@ protected function generateTableTca(TableDefinition $tableDefinition, array $bas
165166
}
166167
$tca['types'][$typeDefinition->getTypeName()] = $this->processTypeDefinition($typeDefinition, $tableDefinition);
167168
if ($tableDefinition->hasTypeField()) {
168-
$tca['ctrl']['typeicon_classes'][$typeDefinition->getTypeName()] = $typeDefinition->getTypeIcon()->iconIdentifier;
169+
if ($typeDefinition->getTypeIcon()->initialized) {
170+
$tca['ctrl']['typeicon_classes'][$typeDefinition->getTypeName()] = $typeDefinition->getTypeIcon()->iconIdentifier;
171+
}
169172
if ($typeDefinition instanceof PageTypeDefinition) {
170173
if ($typeDefinition->getPageIconSet()->iconHideInMenu->initialized) {
171174
$tca['ctrl']['typeicon_classes'][$typeDefinition->getTypeName() . '-hideinmenu'] = $typeDefinition->getPageIconSet()->iconHideInMenu->iconIdentifier;
@@ -176,7 +179,7 @@ protected function generateTableTca(TableDefinition $tableDefinition, array $bas
176179
}
177180
}
178181
if ($tableDefinition->contentType === ContentType::RECORD_TYPE) {
179-
if ($isNewTable || !isset($baseTca[$tableDefinition->table]['ctrl']['typeicon_classes']['default'])) {
182+
if ($typeDefinition->getTypeIcon()->initialized && ($isNewTable || !isset($baseTca[$tableDefinition->table]['ctrl']['typeicon_classes']['default']))) {
180183
$tca['ctrl']['typeicon_classes']['default'] ??= $typeDefinition->getTypeIcon()->iconIdentifier;
181184
}
182185
if ($tableDefinition->hasTypeField()) {
@@ -262,6 +265,10 @@ protected function fillTypeFieldSelectItems(): void
262265
continue;
263266
}
264267
foreach ($tableDefinition->contentTypeDefinitionCollection as $typeDefinition) {
268+
$typeName = $typeDefinition->getTypeName();
269+
if ($tableDefinition->contentType === ContentType::PAGE_TYPE && PageTypeNameValidator::isExistingPageType($typeName)) {
270+
continue;
271+
}
265272
$languagePathTitle = $typeDefinition->getLanguagePathTitle();
266273
if ($this->languageFileRegistry->isset($typeDefinition->getName(), $languagePathTitle)) {
267274
$label = $languagePathTitle;
@@ -274,13 +281,14 @@ protected function fillTypeFieldSelectItems(): void
274281
} else {
275282
$description = $typeDefinition->getDescription();
276283
}
284+
$icon = $typeDefinition->getTypeIcon();
277285
ExtensionManagementUtility::addTcaSelectItem(
278286
$typeDefinition->getTable(),
279287
$tableDefinition->typeField,
280288
[
281289
'label' => $label,
282-
'value' => $typeDefinition->getTypeName(),
283-
'icon' => $typeDefinition->getTypeIcon()->iconIdentifier,
290+
'value' => $typeName,
291+
'icon' => $icon->initialized ? $icon->iconIdentifier : null,
284292
'group' => $typeDefinition->getGroup(),
285293
'description' => $description,
286294
]

Classes/Loader/ContentBlockLoader.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,22 @@ protected function loadSingleContentBlock(
246246
$yaml = $this->basicsService->applyBasics($basicsRegistry, $yaml);
247247
$iconIdentifier = ContentBlockPathUtility::getIconNameWithoutFileExtension();
248248
$contentBlockIcon = new ContentTypeIcon();
249+
$withFallback = true;
250+
if ($contentType === ContentType::FILE_TYPE) {
251+
$withFallback = false;
252+
}
253+
if ($contentType === ContentType::PAGE_TYPE && PageTypeNameValidator::isExistingPageType($typeName)) {
254+
$withFallback = false;
255+
}
249256
$baseIconInput = new ContentTypeIconResolverInput(
250257
name: $name,
251258
absolutePath: $absolutePath,
252259
extension: $extensionKey,
253260
identifier: $iconIdentifier,
254261
contentType: $contentType,
255262
table: $table,
256-
typeName: $typeName
263+
typeName: $typeName,
264+
withFallback: $withFallback,
257265
);
258266
$this->iconProcessor->addInstruction($contentBlockIcon, $baseIconInput);
259267
$pageIconSet = null;

Classes/Service/Icon/ContentTypeIconResolver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ public static function getDefaultContentTypeIcon(ContentType $contentType): stri
7474
$iconPath = match ($contentType) {
7575
ContentType::CONTENT_ELEMENT => 'EXT:content_blocks/Resources/Public/Icons/DefaultContentElementIcon.svg',
7676
ContentType::PAGE_TYPE => 'EXT:content_blocks/Resources/Public/Icons/DefaultPageTypeIcon.svg',
77-
// @todo FileType doesn't need an icon, but this is right now required for ContentTypeInterface.
78-
ContentType::FILE_TYPE, ContentType::RECORD_TYPE => 'EXT:content_blocks/Resources/Public/Icons/DefaultRecordTypeIcon.svg',
77+
ContentType::RECORD_TYPE => 'EXT:content_blocks/Resources/Public/Icons/DefaultRecordTypeIcon.svg',
78+
ContentType::FILE_TYPE => throw new \InvalidArgumentException('File Types cannot have any icons.', 1748194506),
7979
};
8080
return $iconPath;
8181
}

Classes/ServiceProvider.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,26 +109,32 @@ public static function getContentBlockIcons(ContainerInterface $container): \Arr
109109
/** @var ContentTypeInterface $typeDefinition */
110110
foreach ($tableDefinition->contentTypeDefinitionCollection as $typeDefinition) {
111111
$icon = $typeDefinition->getTypeIcon();
112-
$iconConfig = [
113-
$icon->iconIdentifier => [
114-
'source' => $icon->iconPath,
115-
'provider' => $icon->iconProvider,
116-
],
117-
];
112+
$iconConfig = [];
113+
if ($icon->initialized) {
114+
$iconConfig = [
115+
$icon->iconIdentifier => [
116+
'source' => $icon->iconPath,
117+
'provider' => $icon->iconProvider,
118+
],
119+
];
120+
}
118121
if ($typeDefinition instanceof PageTypeDefinition) {
119-
if ($typeDefinition->getPageIconSet()->iconHideInMenu->iconIdentifier !== '') {
122+
if ($typeDefinition->getPageIconSet()->iconHideInMenu->initialized) {
120123
$hideInMenuIcon = $typeDefinition->getPageIconSet()->iconHideInMenu;
121124
$iconConfig[$hideInMenuIcon->iconIdentifier] = [
122125
'source' => $hideInMenuIcon->iconPath,
123126
];
124127
}
125-
if ($typeDefinition->getPageIconSet()->iconRoot->iconIdentifier !== '') {
128+
if ($typeDefinition->getPageIconSet()->iconRoot->initialized) {
126129
$rootIcon = $typeDefinition->getPageIconSet()->iconRoot;
127130
$iconConfig[$rootIcon->iconIdentifier] = [
128131
'source' => $rootIcon->iconPath,
129132
];
130133
}
131134
}
135+
if ($iconConfig === []) {
136+
continue;
137+
}
132138
$arrayObject->exchangeArray(array_merge($arrayObject->getArrayCopy(), $iconConfig));
133139
}
134140
}

Classes/Validation/PageTypeNameValidator.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,27 @@ class PageTypeNameValidator
3535
PageRepository::DOKTYPE_SYSFOLDER,
3636
];
3737

38+
/** @var list<int> $nonOverridablePageTypes */
39+
protected static array $nonOverridablePageTypes = [
40+
PageRepository::DOKTYPE_SPACER,
41+
PageRepository::DOKTYPE_SYSFOLDER,
42+
];
43+
44+
public static function isExistingPageType(string|int $typeName): bool
45+
{
46+
$integerTypeName = (int)$typeName;
47+
$isExistingPageType = in_array($integerTypeName, self::$reservedPageTypes, true);
48+
return $isExistingPageType;
49+
}
50+
3851
public static function validate(string|int $typeName, string $contentBlockName): void
3952
{
4053
$integerTypeName = (int)$typeName;
41-
if (!MathUtility::canBeInterpretedAsInteger($typeName) || $integerTypeName < 0 || in_array($integerTypeName, self::$reservedPageTypes, true)) {
54+
if (!MathUtility::canBeInterpretedAsInteger($typeName) || $integerTypeName < 0 || in_array($integerTypeName, self::$nonOverridablePageTypes, true)) {
4255
throw new \InvalidArgumentException(
43-
'Invalid value "' . $typeName . '" for "typeName" in ContentBlock "' . $contentBlockName . '". Value must be a positive integer and not one of the reserved page types: '
44-
. implode(', ', self::$reservedPageTypes),
56+
'Invalid value "' . $typeName . '" for "typeName" in ContentBlock "' .
57+
$contentBlockName . '". Value must be a positive integer and not one of the non-overridable page types: '
58+
. implode(', ', self::$nonOverridablePageTypes),
4559
1689287031
4660
);
4761
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
identifier: TYPO3/External
2+
fields:
3+
- identifier: palette_external
4+
type: Palette
5+
fields:
6+
- identifier: url
7+
useExistingField: true
8+
- identifier: target
9+
useExistingField: true
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
identifier: TYPO3/Shortcut
2+
fields:
3+
- identifier: shortcut_mode
4+
useExistingField: true
5+
- identifier: shortcut
6+
useExistingField: true

Documentation/ChangeLog/1.3/Index.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,49 @@ search and replace: `<be:link.editRecord` -> `<cb:link.editRecord` and
131131
import in case you didn't use any other ViewHelper in the `be` namespace.
132132
Importing the `cb` namespace it optional as it is registered globally.
133133

134+
Re-definition of Core Page Types
135+
--------------------------------
136+
137+
It is now possible to re-define the Core Pages Types of TYPO3:
138+
139+
* Standard (1)
140+
* Link to External URL (3)
141+
* Shortcut (4)
142+
* Backend User Section (6)
143+
* Mount Point (7)
144+
145+
This is especially useful if you need custom fields for Core Page Types, but
146+
it's not possible to use a custom Page Type like for Shortcuts or External
147+
Links. This feature should not be used in third-party extensions, as this would
148+
make it impossible for users to define the Page Type themselves.
149+
150+
Examples
151+
________
152+
153+
Override Page Type "External URL":
154+
155+
.. code-block:: yaml
156+
157+
name: vendor/external-page
158+
typeName: 3
159+
fields:
160+
- identifier: additional_field
161+
type: Text
162+
- identifier: TYPO3/External
163+
type: Basic
164+
165+
Override Page Type "Shortcut":
166+
167+
.. code-block:: yaml
168+
169+
name: vendor/shortcut-page
170+
typeName: 4
171+
fields:
172+
- identifier: additional_field
173+
type: Text
174+
- identifier: TYPO3/Shortcut
175+
type: Basic
176+
134177
Default config
135178
--------------
136179

Documentation/YamlReference/ContentTypes/PageTypes/Index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Here you can find all :ref:`common root options <yaml_reference_common>`.
3636
:type: integer
3737

3838
The :yaml:`typeName` has to be a numerical value. There are some reserved
39-
numbers, which you can't use either: 1, 3, 4, 6, 7, 199, 254, 255.
39+
numbers, which you can't use either: 199, 254.
4040

4141
.. code-block:: yaml
4242

0 commit comments

Comments
 (0)