Your IP : 216.73.217.13


Current Path : /var/www/surf/TYPO3/vendor/mask/mask/Classes/CodeGenerator/
Upload File :
Current File : /var/www/surf/TYPO3/vendor/mask/mask/Classes/CodeGenerator/HtmlCodeGenerator.php

<?php

declare(strict_types=1);

/*
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

namespace MASK\Mask\CodeGenerator;

use MASK\Mask\Definition\ElementTcaDefinition;
use MASK\Mask\Definition\TableDefinitionCollection;
use MASK\Mask\Definition\TcaFieldDefinition;
use MASK\Mask\Enumeration\FieldType;
use MASK\Mask\Loader\LoaderInterface;
use MASK\Mask\Utility\AffixUtility;
use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
 * Generates the html and fluid for mask content elements
 * @internal
 */
class HtmlCodeGenerator
{
    protected LoaderInterface $loader;
    protected int $indent = 4;
    protected ?TableDefinitionCollection $tableDefinitionCollection = null;

    public function __construct(LoaderInterface $loader)
    {
        $this->loader = $loader;
    }

    /**
     * Generates Fluid HTML for Contentelements
     */
    public function generateHtml(string $elementKey, string $table): string
    {
        $this->tableDefinitionCollection = $this->loader->load();
        $element = $this->tableDefinitionCollection->loadElement($table, $elementKey);

        if (!$element instanceof ElementTcaDefinition) {
            return '';
        }

        $html = [];
        foreach ($element->getRootTcaFields() as $field) {
            $part = $this->generateFieldHtml($field, $element, $table);
            if ($part !== '') {
                $html[] = $part;
            }
        }
        if (count($html) > 0) {
            return implode("\n", $html) . "\n";
        }
        return '';
    }

    /**
     * Generates HTML for a field
     */
    protected function generateFieldHtml(TcaFieldDefinition $field, ElementTcaDefinition $element, string $table, string $datafield = 'data', int $depth = 0): string
    {
        $html = [];
        if (!$field->hasFieldType($element->elementDefinition->key) || !$field->getFieldType($element->elementDefinition->key)->isRenderable()) {
            return '';
        }
        switch ((string)$field->getFieldType($element->elementDefinition->key)) {
            case FieldType::SELECT:
                if (($field->realTca['config']['foreign_table'] ?? '') !== '') {
                    $html[] = $this->drawWhitespace(0 + $depth) . '<f:for each="{' . $datafield . '.' . $field->fullKey . '_items}" as="' . $datafield . '_item' . '">';
                    $html[] = $this->drawWhitespace(1 + $depth) . '<div>{' . $datafield . '_item.uid}' . '</div>';
                    $html[] = $this->drawWhitespace(0 + $depth) . '</f:for>';
                } elseif (in_array(($field->realTca['config']['renderType'] ?? ''), ['selectCheckBox', 'selectSingleBox', 'selectMultipleSideBySide'], true)) {
                    $html[] = $this->drawWhitespace(0 + $depth) . '<f:for each="{' . $datafield . '.' . $field->fullKey . '_items}" as="' . $datafield . '_item' . '">';
                    $html[] = $this->drawWhitespace(1 + $depth) . '<div>{' . $datafield . '_item}' . '</div>';
                    $html[] = $this->drawWhitespace(0 + $depth) . '</f:for>';
                } else {
                    $html[] = $this->drawWhitespace(0 + $depth) . $this->getVariableViewHelper($datafield, $field->fullKey);
                    $html[] = $this->drawWhitespace(0 + $depth) . '<f:switch expression="{' . $this->getVariableName($field->fullKey) . '}">';
                    foreach ($field->realTca['config']['items'] ?? [] as $item) {
                        $html[] = $this->drawWhitespace(1 + $depth) . '<f:case value="' . ($item[1] ?? $item['value']) . '">';
                        $html[] = $this->drawWhitespace(2 + $depth) . '{' . $this->getVariableName($field->fullKey) . '}';
                        $html[] = $this->drawWhitespace(1 + $depth) . '</f:case>';
                    }
                    $html[] = $this->drawWhitespace(0 + $depth) . '</f:switch>';
                }
                break;
            case FieldType::CATEGORY:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:for each="{' . $datafield . '.' . $field->fullKey . '_items}" as="category">';
                $html[] = $this->drawWhitespace(1 + $depth) . '<div>{category.title}</div>';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:for>';
                break;
            case FieldType::RADIO:
            case FieldType::CHECK:
                $html[] = $this->drawWhitespace(0 + $depth) . $this->getVariableViewHelper($datafield, $field->fullKey);
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $this->getVariableName($field->fullKey) . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '<f:then>';
                $html[] = $this->drawWhitespace(2 + $depth) . '<f:comment><!-- Do this, if checked --></f:comment>';
                $html[] = $this->drawWhitespace(1 + $depth) . '</f:then>';
                $html[] = $this->drawWhitespace(1 + $depth) . '<f:else>';
                $html[] = $this->drawWhitespace(2 + $depth) . '<f:comment><!-- Else do this --></f:comment>';
                $html[] = $this->drawWhitespace(1 + $depth) . '</f:else>';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';

                break;
            case FieldType::CONTENT:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '<f:for each="{' . $datafield . '.' . $field->fullKey . '}" as="' . $datafield . '_item' . '">';
                $html[] = $this->drawWhitespace(2 + $depth) . '<f:cObject typoscriptObjectPath="lib.tx_mask.content">{' . $datafield . '_item.uid}</f:cObject>';
                $html[] = $this->drawWhitespace(1 + $depth) . '</f:for>';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::DATE:
            case FieldType::TIMESTAMP:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '{' . $datafield . '.' . $field->fullKey . ' -> f:format.date(format: \'d.m.Y\')}';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::DATETIME:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '{' . $datafield . '.' . $field->fullKey . ' -> f:format.date(format: \'d.m.Y - H:i:s\')}';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::FILE:
                if ($field->imageoverlayPalette) {
                    $html[] = $this->drawWhitespace(0 + $depth) . '<f:for each="{' . $datafield . '.' . $field->fullKey . '}" as="file">';
                    $html[] = $this->drawWhitespace(1 + $depth) . '<f:image image="{file}" width="200" />';
                    $html[] = $this->drawWhitespace(1 + $depth) . '{file.description}';
                    $html[] = $this->drawWhitespace(0 + $depth) . '</f:for>';
                } else {
                    $html[] = $this->drawWhitespace(0 + $depth) . '<f:for each="{' . $datafield . '.' . $field->fullKey . '}" as="file">';
                    $html[] = $this->drawWhitespace(1 + $depth) . '<a href="{file.originalFile.publicUrl}" target="_blank">{f:if(condition: file.title, then: file.title, else: file.name)}</a>';
                    $html[] = $this->drawWhitespace(1 + $depth) . '{file.description}';
                    $html[] = $this->drawWhitespace(1 + $depth) . '<f:format.bytes>{file.size}</f:format.bytes>';
                    $html[] = $this->drawWhitespace(0 + $depth) . '</f:for>';
                }
                break;
            case FieldType::MEDIA:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:for each="{' . $datafield . '.' . $field->fullKey . '}" as="file">';
                $html[] = $this->drawWhitespace(1 + $depth) . '<f:media file="{file}" width="200" />';
                $html[] = $this->drawWhitespace(1 + $depth) . '{file.description}';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:for>';
                break;
            case FieldType::FLOAT:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '{' . $datafield . '.' . $field->fullKey . ' -> f:format.number(decimals: \'2\', decimalSeparator: \',\', thousandsSeparator: \'.\')}';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::INLINE:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '<ul>';
                $html[] = $this->drawWhitespace(2 + $depth) . '<f:for each="{' . $datafield . '.' . $field->fullKey . '}" as="' . $datafield . '_item' . '">';
                $html[] = $this->drawWhitespace(3 + $depth) . '<li>';
                foreach ($this->tableDefinitionCollection->loadInlineFields($field->fullKey, $element->elementDefinition->key, $element->elementDefinition) as $inlineField) {
                    $html[] = $this->generateFieldHtml($inlineField, $element, $field->fullKey, $datafield . '_item', 4 + $depth);
                }
                $html[] = $this->drawWhitespace(3 + $depth) . '</li>';
                $html[] = $this->drawWhitespace(2 + $depth) . '</f:for>';
                $html[] = $this->drawWhitespace(1 + $depth) . '</ul>';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::PALETTE:
                foreach ($this->tableDefinitionCollection->loadInlineFields($field->fullKey, $element->elementDefinition->key, $element->elementDefinition) as $paletteField) {
                    $part = $this->generateFieldHtml($paletteField, $element, $table, $datafield, $depth);
                    if ($part !== '') {
                        $html[] = $part;
                    }
                }
                break;
            case FieldType::GROUP:
                if ((new Typo3Version())->getMajorVersion() > 11 || ($field->realTca['config']['internal_type'] ?? '') !== 'folder') {
                    $html[] = $this->drawWhitespace(0 + $depth) . '<f:for each="{' . $datafield . '.' . $field->fullKey . '_items}" as="' . $datafield . '_item' . '">';
                    $html[] = $this->drawWhitespace(1 + $depth) . '<div>{' . $datafield . '_item.uid}' . '</div>';
                    $html[] = $this->drawWhitespace(0 + $depth) . '</f:for>';
                    break;
                }
                // no break intended.
            case FieldType::STRING:
            case FieldType::INTEGER:
            case FieldType::COLORPICKER:
            case FieldType::FOLDER:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '{' . $datafield . '.' . $field->fullKey . '}';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::EMAIL:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '<f:link.email email="{' . $datafield . '.' . $field->fullKey . '}"/>';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::LINK:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '<f:link.typolink parameter="{' . $datafield . '.' . $field->fullKey . '}"></f:link.typolink>';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::RICHTEXT:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '{' . $datafield . '.' . $field->fullKey . ' -> f:format.html()}';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::TEXT:
                $html[] = $this->drawWhitespace(0 + $depth) . '<f:if condition="{' . $datafield . '.' . $field->fullKey . '}">';
                $html[] = $this->drawWhitespace(1 + $depth) . '{' . $datafield . '.' . $field->fullKey . ' -> f:format.nl2br()}';
                $html[] = $this->drawWhitespace(0 + $depth) . '</f:if>';
                break;
            case FieldType::SLUG:
                $html[] = $this->drawWhitespace(0 + $depth) . '<div id="{' . $datafield . '.' . $field->fullKey . '}"></div>';
                break;
        }
        return implode("\n", $html);
    }

    protected function getVariableViewHelper(string $datafield, string $fieldKey): string
    {
        return '<f:variable name="' . $this->getVariableName($fieldKey) . '" value="{' . $datafield . '.' . $fieldKey . '}"/>';
    }

    protected function getVariableName(string $fieldKey): string
    {
        $key = AffixUtility::hasMaskPrefix($fieldKey) ? AffixUtility::removeMaskPrefix($fieldKey) : $fieldKey;
        return GeneralUtility::underscoredToLowerCamelCase($key);
    }

    protected function drawWhitespace(int $times = 1): string
    {
        return str_repeat(' ', $this->indent * $times);
    }
}