Skip to content

Commit

Permalink
[FEATURE] Allow to use core bodytext field as text
Browse files Browse the repository at this point in the history
Since the beginning of this extension, the core
bodytext field was treated as richtext field. This
was hard coded and there was no way to use it as a
normal text field.

In order to make it possible to do so, the
TcaFieldDefinition is extended by the option
bodytextTypeByElement. This property holds the
type (text or richtext) for the bodytext field
depending on the element it is used in. Helper
methods were added, to get the appropriate type.

Now that the type can be distinguished, it has to
be selectable in the backend module. This is done
in the AjaxController in the method existingTca.
This method checks, if we are searching for a text
or richtext field and the core field bodytext is
in the list.

There is also a bugfix included:
The columnsOverrides for the bodytext field is now
only added, if the element uses this field. This
prevents unnecessary TCA generation.

Fixes: Gernott#408
  • Loading branch information
nhovratov committed Apr 15, 2022
1 parent d561cf2 commit c1405c8
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 58 deletions.
25 changes: 20 additions & 5 deletions Classes/CodeGenerator/TcaCodeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
namespace MASK\Mask\CodeGenerator;

use InvalidArgumentException;
use MASK\Mask\Definition\ElementTcaDefinition;
use MASK\Mask\Definition\PaletteDefinition;
use MASK\Mask\Definition\TableDefinition;
use MASK\Mask\Definition\TableDefinitionCollection;
Expand Down Expand Up @@ -194,7 +195,21 @@ public function setElementsTca(): void
[$prependTabs, $fields] = $this->generateShowItem($prependTabs, $element->key, 'tt_content');

$GLOBALS['TCA']['tt_content']['ctrl']['typeicon_classes'][$cTypeKey] = 'mask-ce-' . $element->key;
$GLOBALS['TCA']['tt_content']['types'][$cTypeKey]['columnsOverrides']['bodytext']['config']['enableRichtext'] = 1;
$elementTca = $this->tableDefinitionCollection->loadElement('tt_content', $element->key);

// Check if the element uses the core bodytext field, and it is of type richtext.
// If so, enable the richtext editor for it.
if ($elementTca instanceof ElementTcaDefinition
&& $elementTca->tcaDefinition->hasField('bodytext')
) {
$bodytext = $elementTca->tcaDefinition->getField('bodytext');
if (
!$bodytext->hasFieldType($element->key)
|| $bodytext->getFieldType($element->key)->equals(FieldType::RICHTEXT)
) {
$GLOBALS['TCA']['tt_content']['types'][$cTypeKey]['columnsOverrides']['bodytext']['config']['enableRichtext'] = 1;
}
}
$GLOBALS['TCA']['tt_content']['types'][$cTypeKey]['showitem'] = $prependTabs . $defaultPalette . $fields . $defaultTabs . $gridelements;
}
}
Expand Down Expand Up @@ -314,12 +329,12 @@ public function generateFieldsTca(string $table): array
continue;
}

if (!$field->type) {
if (!$field->hasFieldType()) {
$field->type = $this->tableDefinitionCollection->getFieldType($field->fullKey, $table);
}

// Inline: Ignore empty inline fields
if ($field->type && $field->type->isParentField() && !$this->tableDefinitionCollection->hasTable($field->fullKey)) {
if ($field->type->isParentField() && !$this->tableDefinitionCollection->hasTable($field->fullKey)) {
continue;
}

Expand Down Expand Up @@ -475,15 +490,15 @@ public function generateTCAColumnsOverrides(string $table): array

// Do not generate any overrides for empty inline fields.
if (
$fieldDefinition->type instanceof FieldType
$fieldDefinition->hasFieldType()
&& $fieldDefinition->type->equals(FieldType::INLINE)
&& $this->tableDefinitionCollection->loadInlineFields($fieldDefinition->fullKey, $element->key)->toArray() === []
) {
continue;
}

// Do not generate any overrides for tabs.
if ($fieldDefinition->type instanceof FieldType && $fieldDefinition->type->equals(FieldType::TAB)) {
if ($fieldDefinition->hasFieldType() && $fieldDefinition->type->equals(FieldType::TAB)) {
continue;
}

Expand Down
15 changes: 12 additions & 3 deletions Classes/Controller/AjaxController.php
Original file line number Diff line number Diff line change
Expand Up @@ -654,17 +654,18 @@ public function existingTca(ServerRequestInterface $request): Response
$table = $request->getQueryParams()['table'];
$type = $request->getQueryParams()['type'];
$fields = ['mask' => [], 'core' => []];
$searchFieldType = FieldType::cast($type);

// Return empty result for non-shareable fields.
if (!FieldType::cast($type)->canBeShared()) {
if (!$searchFieldType->canBeShared()) {
return new JsonResponse($fields);
}

foreach (($GLOBALS['TCA'][$table]['columns'] ?? []) as $tcaField => $tcaConfig) {
$isMaskField = AffixUtility::hasMaskPrefix($tcaField);
// Skip the field, if it is not a mask field, AND it is not in the allow-list
// AND it is also not an already defined field in the configuration.
// This may be an extension field or a core field, which was previously allowed.
// This may be an extension field or a core field (which was allowed in former Mask versions).
if (
!$isMaskField
&& !in_array($tcaField, $allowedFields[$table] ?? [], true)
Expand All @@ -677,7 +678,15 @@ public function existingTca(ServerRequestInterface $request): Response
continue;
}

if ($this->tableDefinitionCollection->getFieldType($tcaField, $table)->equals($type)) {
// Add the field, if the field type matches with the search type
// OR the field is the bodytext field, and we search for a text or textarea field.
$fieldType = $this->tableDefinitionCollection->getFieldType($tcaField, $table);
if (
$fieldType->equals($type)
|| (
$tcaField === 'bodytext' && $searchFieldType->isTextareaField()
)
) {
$key = $isMaskField ? 'mask' : 'core';
if ($isMaskField) {
$label = $this->tableDefinitionCollection->findFirstNonEmptyLabel($table, $tcaField);
Expand Down
4 changes: 2 additions & 2 deletions Classes/Controller/FieldsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function loadElement(ServerRequestInterface $request): Response
$element = $this->tableDefinitionCollection->loadElement($table, $elementKey);
$json['fields'] = [];
if ($element) {
$json['fields'] = $this->addFields($element->tcaDefinition->toArray(), $table, $elementKey);
$json['fields'] = $this->addFields($element->getRootTcaFields()->toArray(), $table, $elementKey);
}

return new JsonResponse($json);
Expand Down Expand Up @@ -123,7 +123,7 @@ protected function addFields(array $fields, string $table, string $elementKey =
$newField['description'] = $this->tableDefinitionCollection->getDescription($elementKey, $newField['key'], $table);
}

$fieldType = $this->tableDefinitionCollection->getFieldType($newField['key'], $table);
$fieldType = $this->tableDefinitionCollection->getFieldType($newField['key'], $table, $elementKey);

// Convert old date format Y-m-d to d-m-Y
$dbType = $field['config']['dbType'] ?? false;
Expand Down
13 changes: 9 additions & 4 deletions Classes/Definition/ElementTcaDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,18 @@ final class ElementTcaDefinition
public function __construct(ElementDefinition $elementDefinition, TcaDefinition $tcaDefinition)
{
$this->elementDefinition = $elementDefinition;
$this->tcaDefinition = new TcaDefinition();
$this->tcaDefinition = $tcaDefinition;
}

foreach ($this->elementDefinition->columns as $field) {
if ($tcaDefinition->hasField($field)) {
$this->tcaDefinition->addField($tcaDefinition->getField($field));
public function getRootTcaFields(): TcaDefinition
{
$tcaDefinition = new TcaDefinition();
foreach ($this->elementDefinition->columns as $column) {
if ($this->tcaDefinition->hasField($column)) {
$tcaDefinition->addField($this->tcaDefinition->getField($column));
}
}
return $tcaDefinition;
}

public function toArray(): array
Expand Down
48 changes: 29 additions & 19 deletions Classes/Definition/TableDefinitionCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,26 @@ public function loadElement(string $table, string $key): ?ElementTcaDefinition
}

$element = $elements->getElement($key);
return new ElementTcaDefinition($element, $tableDefinition->tca);
$tcaDefinition = new TcaDefinition();
foreach ($element->columns as $fieldKey) {
if ($tableDefinition->tca->hasField($fieldKey)) {
$availableTcaField = $tableDefinition->tca->getField($fieldKey);
$tcaDefinition->addField($availableTcaField);
if ($availableTcaField->hasFieldType() && $availableTcaField->type->equals(FieldType::PALETTE)) {
$paletteFields = $this->loadInlineFields($availableTcaField->fullKey, $element->key);
foreach ($paletteFields as $paletteField) {
$tcaDefinition->addField($paletteField);
}
}
}
}

return new ElementTcaDefinition($element, $tcaDefinition);
}

/**
* Loads all the inline fields of an inline-field, recursively!
* Not specifying an element key means, the parent key has to be an inline table.
*
* @param string $parentKey
* @param string $elementKey
* @return NestedTcaFieldDefinitions
*/
public function loadInlineFields(string $parentKey, string $elementKey): NestedTcaFieldDefinitions
{
Expand Down Expand Up @@ -193,8 +203,8 @@ public function loadInlineFields(string $parentKey, string $elementKey): NestedT
continue;
}

// This can be called very early, so ignore core fields.
if (!$field->isCoreField) {
// Check if FieldType is available
if ($field->hasFieldType()) {
$fieldType = $this->getFieldType($field->fullKey, $tableDefinition->table);
if ($fieldType->isParentField()) {
foreach ($this->loadInlineFields($field->fullKey, $elementKey) as $inlineField) {
Expand All @@ -210,31 +220,31 @@ public function loadInlineFields(string $parentKey, string $elementKey): NestedT
return $nestedTcaFields;
}

public function getFieldType(string $fieldKey, string $table = 'tt_content'): FieldType
public function getFieldType(string $fieldKey, string $table = 'tt_content', string $elmentKey = ''): FieldType
{
return FieldType::cast($this->getFieldTypeString($fieldKey, $table));
return FieldType::cast($this->getFieldTypeString($fieldKey, $table, $elmentKey));
}

/**
* Returns the formType of a field in an element
* @internal
*/
public function getFieldTypeString(string $fieldKey, string $table = 'tt_content'): string
public function getFieldTypeString(string $fieldKey, string $table = 'tt_content', string $elementKey = ''): string
{
// @todo Allow bodytext to be normal TEXT field.
if ($fieldKey === 'bodytext' && $table === 'tt_content') {
return FieldType::RICHTEXT;
}

$fieldDefinition = $this->loadField($table, $fieldKey);

if ($fieldDefinition !== null && !$fieldDefinition->isCoreField) {
if ($fieldDefinition instanceof TcaFieldDefinition) {
// If type is already known, return it.
if ($fieldDefinition->type) {
return (string)$fieldDefinition->type;
if ($fieldDefinition->hasFieldType($elementKey)) {
return (string)$fieldDefinition->getFieldType($elementKey);
}

return FieldTypeUtility::getFieldType($fieldDefinition->toArray(), $fieldDefinition->fullKey);
try {
return FieldTypeUtility::getFieldType($fieldDefinition->toArray(), $fieldDefinition->fullKey);
} catch (InvalidArgumentException $e) {
// For core fields this exception might pop up, because in older
// Mask versions no type was defined directly in the definition.
}
}

// If field could not be found in field definition, check for global TCA.
Expand Down
36 changes: 36 additions & 0 deletions Classes/Definition/TcaFieldDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ final class TcaFieldDefinition
*/
public $inlineParentByElement = [];

/**
* @var array<string, FieldType>
*/
public $bodytextTypeByElement = [];

/**
* @var string
*/
Expand Down Expand Up @@ -195,6 +200,11 @@ public static function createFromFieldArray(array $definition): TcaFieldDefiniti
$tcaFieldDefinition->type = FieldType::cast(FieldType::RICHTEXT);
}

// The core field bodytext used to be hard coded as richtext in Mask versions < v7.2
if (!$tcaFieldDefinition->type instanceof FieldType && $definition['key'] === 'bodytext') {
$tcaFieldDefinition->type = FieldType::cast(FieldType::RICHTEXT);
}

// If the field is not a core field and the field type couldn't be resolved by now, resolve type by tca config.
if (!$tcaFieldDefinition->type instanceof FieldType && !$tcaFieldDefinition->isCoreField) {
$tcaFieldDefinition->type = FieldType::cast(FieldTypeUtility::getFieldType($tcaFieldDefinition->toArray(), $tcaFieldDefinition->fullKey));
Expand All @@ -215,6 +225,14 @@ public static function createFromFieldArray(array $definition): TcaFieldDefiniti
}
}

if (!empty($definition['bodytextTypeByElement'])) {
foreach ($definition['bodytextTypeByElement'] as $elementKey => $bodytextType) {
$tcaFieldDefinition->bodytextTypeByElement[$elementKey] = FieldType::cast($bodytextType);
}
// Unset the normal type
$tcaFieldDefinition->type = null;
}

if (isset($definition['label'])) {
if (is_array($definition['label'])) {
$tcaFieldDefinition->labelByElement = $definition['label'];
Expand Down Expand Up @@ -550,4 +568,22 @@ protected static function migrateTCA(array $definition, TcaFieldDefinition $tcaF

return $definition;
}

public function hasFieldType(string $elementKey = ''): bool
{
return $this->type instanceof FieldType || ($elementKey !== '' && !empty($this->bodytextTypeByElement));
}

public function getFieldType(string $elementKey = ''): FieldType
{
if (!$this->hasFieldType($elementKey)) {
throw new \OutOfBoundsException('The field "' . $this->fullKey . '" does not have a defined field type.', 1650054092);
}

if ($this->type instanceof FieldType) {
return $this->type;
}

return $this->bodytextTypeByElement[$elementKey] ?? new FieldType(FieldType::RICHTEXT);
}
}
6 changes: 6 additions & 0 deletions Classes/Domain/Repository/StorageRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
namespace MASK\Mask\Domain\Repository;

use MASK\Mask\ConfigurationLoader\ConfigurationLoaderInterface;
use MASK\Mask\Definition\ElementTcaDefinition;
use MASK\Mask\Definition\TableDefinitionCollection;
use MASK\Mask\Definition\TcaFieldDefinition;
use MASK\Mask\Enumeration\FieldType;
Expand Down Expand Up @@ -302,6 +303,11 @@ protected function addFieldsToJson(array $jsonAdd, array $fields, string $elemen
}
}

if ($fieldAdd['key'] === 'bodytext') {
$fieldAdd['bodytextTypeByElement'][$elementKey] = $fieldAdd['type'];
unset($fieldAdd['type']);
}

// Add tca entry for field
$jsonAdd[$table]['tca'][$field['key']] = $fieldAdd;

Expand Down
5 changes: 5 additions & 0 deletions Classes/Enumeration/FieldType.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,9 @@ public function isFileReference(): bool
{
return in_array($this->value, [self::FILE, self::MEDIA], true);
}

public function isTextareaField(): bool
{
return in_array($this->value, [self::TEXT, self::RICHTEXT], true);
}
}
Loading

0 comments on commit c1405c8

Please sign in to comment.