Building a TYPO3 extension in Extbase/Fluid

Flexform: use section for indefinitely repeatable form fields

This chapter takes on a subject that I couldn’t find a solution for in the official TYPO3 documentation. In a model of my extension I needed a set of two fields which can be filled repeatedly – but creating an additional model would have been an overload. So I thought of Flexforms. From the use of the DCE extension I knew it was possible to do what I needed – but in the documentation I couldn’t find how. I later found a post in the TYPO3 forum – but when I needed it, the website could not be loaded.

Here’s what it will look like:

Screenshot of the flexform for the projects list

So I filtered the information from ext/dce/Classes/Components/ContentElementGenerator/OutputTcaAndFlexForm.php->renderFlexformXml(). The thing is: there’s an immense amount of nesting necessary. But see for yourself. My example is about the idea of adding several projects to a database record of my model, each project containing two simple text fields: title and description.

Note that you need <type> and <el> three times!

<?xml version="1.0"?>
<T3DataStructure>
    <meta>
        <langDisable>1</langDisable>
    </meta>
    <sheets>
        <sheet.projects>
            <ROOT>
                <type>array</type>
                <el>
                    <projects>
                        <title>LLL:EXT:myextension/Resources/Private/Language/locallang_be.xlf:projects.flexformTitle</title>
                        <type>array</type>
                        <section>1</section>
                        <el>
                            <projectSingle>
                                <title>LLL:EXT:myextension/Resources/Private/Language/locallang_be.xlf:projects.projectSingleTitle</title>
                                <type>array</type>
                                <el>
                                    <projectTitle>
                                        <TCEforms>
                                            <label>LLL:EXT:myextension/Resources/Private/Language/locallang_be.xlf:projects.projectTitle</label>
                                            <config>
                                                <type>input</type>
                                                <size>255</size>
                                                <eval>trim</eval>
                                            </config>
                                        </TCEforms>
                                    </projectTitle>
                                    <projectDescription>
                                        <TCEforms>
                                            <label>LLL:EXT:myextension/Resources/Private/Language/locallang_be.xlf:projects.description</label>
                                            <config>
                                                <type>input</type>
                                                <size>255</size>
                                                <eval>trim</eval>
                                            </config>
                                        </TCEforms>
                                    </projectDescription>>
                                </el>
                            </projectSingle>
                        </el>
                    </projects>
                </el>
            </ROOT>
        </sheet.projects>
    </sheets>
</T3DataStructure>
</T3DataStructure>

Make the data available in your Fluid template

Add a FlexformProcessing class to your extension, e.g. in /Classes/Utility

<?php
namespace Vendor\YourExtension\Utility;

use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Service\FlexFormService;

class ProjectsProcessor
{
    /**
     * returns the projects (stored in the database as flexform XML) as an array for fluid
     */

    public static function projectsArray($projectsXml)
    {
        $flexformService = GeneralUtility::makeInstance(FlexFormService::class);
        $xmlArray = $flexformService->convertFlexFormContentToArray($projectsXml);

        $projects = [];

        if (isset($xmlArray['projects'])) {
            foreach ($xmlArray['projects'] as $projectData) {
                $projects[] = $projectData['projectSingle'];
            }
        }

        return $projects;
    }
}
    }
}

Call ProjectsProcessor::projectsArray() in your Domain Model getter function:

<?php
namespace Vendor\YourExtension\Domain\Model;

use Vendor\YourExtension\Utility\ProjectsProcessor;

class YourModel extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
    /**
     * is a flexform XML string
     * will be returned as an array by getApplicationProjects()
     * @var string
     */

    protected $projects = '';

    /**
     * $projects is a flexform XML string
     * @return array
     */

    public function getProjects()
    {
        return ProjectsProcessor::projectsArray($this->projects);
    }

    /**
     * @param string $projects
     + @return void
     */

    public function setProjects($projects)
    {
        $this->projects = $projects;
    }
}
    }
}

Call the projects in your Fluid Template:

<f:for each="{yourModel.projects}" as="project">
    <h3>{project.projectTitle}</h3>
    <p>{project.projectDescription>}</p>
</f:for>
</f:for>