Add files to template (#2)

Allow to implement custom templates working with files, e.g. providing a
thumbnail, link to full file, etc.
This commit is contained in:
Daniel Siepmann 2023-07-24 14:13:08 +02:00 committed by GitHub
parent e635b66d36
commit 5bb586a19a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 222 additions and 22 deletions

View file

@ -131,6 +131,9 @@ jobs:
sleep 1 sleep 1
done done
- name: Install graphicsmagick
run: sudo apt-get install -y graphicsmagick
- name: Install dependencies - name: Install dependencies
run: composer req "typo3/cms-core:${{ matrix.typo3-version }}" --prefer-dist --no-progress --no-interaction run: composer req "typo3/cms-core:${{ matrix.typo3-version }}" --prefer-dist --no-progress --no-interaction

View file

@ -36,19 +36,29 @@ final class FileCollectionElement extends AbstractFormElement
public function setProperty(string $key, $value): void public function setProperty(string $key, $value): void
{ {
if ($key === 'fileCollection' && is_array($value)) { if ($key === 'fileCollection' && is_array($value)) {
$this->setProperty('options', $this->getOptions($value)); $this->setFileCollection($value);
return; return;
} }
parent::setProperty($key, $value); parent::setProperty($key, $value);
} }
/**
* @param array<string, string> $value
*/
private function setFileCollection(array $value): void
{
$files = $this->getFiles($value);
$this->setProperty('files', $files);
$this->setProperty('options', $this->getOptions($value, $files));
}
/** /**
* @param array<string, string> $configuration * @param array<string, string> $configuration
* *
* @return array<string, string> * @return FileInterface[]
*/ */
public function getOptions(array $configuration): array private function getFiles(array $configuration): array
{ {
$uid = (int)($configuration['uid'] ?? 0); $uid = (int)($configuration['uid'] ?? 0);
$collection = $this->getRepository()->findByUid($uid); $collection = $this->getRepository()->findByUid($uid);
@ -60,12 +70,20 @@ final class FileCollectionElement extends AbstractFormElement
$collection->loadContents(); $collection->loadContents();
} }
$options = []; return $collection->getItems();
foreach ($collection->getItems() as $file) { }
if (!$file instanceof FileInterface) {
continue;
}
/**
* @param array<string, string> $configuration
* @param FileInterface[] $files
*
* @return array<string, string>
*/
public function getOptions(array $configuration, array $files): array
{
$options = [];
foreach ($files as $file) {
$options = $this->addOption($configuration, $options, $file); $options = $this->addOption($configuration, $options, $file);
} }

View file

@ -22,6 +22,24 @@ Use a free identifier:
80 = EXT:form_file_collection/Configuration/Form/Setup.yaml 80 = EXT:form_file_collection/Configuration/Form/Setup.yaml
} }
No template is configured by default, choose one of the existing ones or provide your own:
.. code:: yaml
TYPO3:
CMS:
Form:
prototypes:
standard:
formElementsDefinition:
FileCollection:
renderingOptions:
# Allows to switch between different rendering like "Checkbox", "MultiCheckbox" or "RadioButton", etc.
templateName: 'MultiCheckbox'
The existing templates will work out of the box.
An additional variable `files` is added for usage within custom templates.
This will register a new form element type ``FileCollection`` that can be used like this: This will register a new form element type ``FileCollection`` that can be used like this:
.. code:: yaml .. code:: yaml
@ -41,20 +59,7 @@ This will register a new form element type ``FileCollection`` that can be used l
# Defines the property to use as label for form element. # Defines the property to use as label for form element.
labelProperty: 'identifier' labelProperty: 'identifier'
No template is configured by default, choose one of the existing ones or provide your own: The two options `valueProperty` and `labelProperty` are used to prepare the `options` variable used by the available default templates.
.. code:: yaml
TYPO3:
CMS:
Form:
prototypes:
standard:
formElementsDefinition:
FileCollection:
renderingOptions:
# Allows to switch between different rendering like "Checkbox", "MultiCheckbox" or "RadioButton", etc.
templateName: 'MultiCheckbox'
Example Example
------- -------

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.7.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="b" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
<style type="text/css">
.st0{fill:#333333;}
.st1{fill:#FFFFFF;}
</style>
<g id="c">
<path class="st0" d="M16,16H0V0h16V16z"/>
<path class="st1" d="M8.9,2.5H5.3c-0.8,0-1.4,0.6-1.4,1.4v8.2c0,0.8,0.6,1.4,1.4,1.4h5.5c0.8,0,1.4-0.6,1.4-1.4V5.7
c0-0.2-0.1-0.4-0.2-0.5L9.4,2.7C9.2,2.6,9.1,2.5,8.9,2.5z M9,4.9V3.5l2.1,2.1H9.7C9.3,5.6,9,5.3,9,4.9z M10,7.9L7.9,10
c-0.1,0.1-0.4,0.1-0.5,0c0,0,0,0,0,0l-1-1c-0.1-0.1-0.1-0.4,0-0.5c0.1-0.1,0.4-0.1,0.5,0l0.8,0.8l1.8-1.8c0.1-0.1,0.4-0.1,0.5,0
C10.1,7.5,10.1,7.8,10,7.9z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 869 B

View file

@ -0,0 +1,76 @@
<?php
return [
'pages' => [
[
'uid' => 3,
'pid' => 1,
'slug' => '/page-3',
'title' => 'Page 3 Custom Template',
],
],
'tt_content' => [
[
'uid' => 3,
'pid' => 3,
'header' => 'Form with custom template',
'header_layout' => '0',
'CType' => 'form_formframework',
'pi_flexform' => '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3FlexForms>
<data>
<sheet index="sDEF">
<language index="lDEF">
<field index="settings.persistenceIdentifier">
<value index="vDEF">EXT:form_file_collection_example/Configuration/Forms/ExampleCustomTemplate.form.yaml</value>
</field>
<field index="settings.overrideFinishers">
<value index="vDEF">0</value>
</field>
</language>
</sheet>
</data>
</T3FlexForms>
',
],
],
'sys_file' => [
[
'uid' => 1,
'pid' => 0,
'missing' => 0,
'storage' => 1,
'type' => 2,
'metadata' => 0,
'identifier' => '/Files/FirstResult.png',
'identifier_hash' => '29b827d0daa29658d8a0d952dfd20f559bbe3bcf',
'folder_hash' => '86d12d536195df2100a5ec04ab80c08f9bed3d31',
'extension' => 'png',
'mime_type' => 'image/png',
'name' => 'FirstResult.png',
'sha1' => 'b13f2bbf275d592534eab659c1430c2702ce31fc',
'size' => '42383',
],
],
'sys_file_collection' => [
[
'uid' => 1,
'pid' => 1,
'title' => 'Example Collection for form',
'files' => 1,
],
],
'sys_file_reference' => [
[
'uid' => 1,
'pid' => 1,
'uid_local' => 1,
'uid_foreign' => 1,
'tablenames' => 'sys_file_collection',
'fieldname' => 'files',
'sorting_foreign' => 1,
'title' => 'Example title for form',
'alternative' => 'Alternative',
],
],
];

View file

@ -0,0 +1,36 @@
renderingOptions:
submitButtonLabel: Submit
partialRootPaths:
20: EXT:form_file_collection_example/Resources/Private/Partials/
type: Form
identifier: test
label: Test
prototypeName: standard
renderables:
-
renderingOptions:
previousButtonLabel: 'Previous step'
nextButtonLabel: 'Next step'
type: Page
identifier: page-1
label: First Step
renderables:
-
type: FileCollectionCustomTemplate
identifier: file-collection-1
label: 'File Collection'
properties:
fileCollection:
uid: 1
-
defaultValue: ''
type: Text
identifier: text-1
label: 'Example text field'
-
renderingOptions:
previousButtonLabel: 'Previous step'
nextButtonLabel: 'Next step'
type: SummaryPage
identifier: summarypage-1
label: 'Summary step'

View file

@ -12,3 +12,8 @@ TYPO3:
renderingOptions: renderingOptions:
# Allows to switch between different rendering like "Checkbox", "MultiCheckbox" or "RadioButton", etc. # Allows to switch between different rendering like "Checkbox", "MultiCheckbox" or "RadioButton", etc.
templateName: 'MultiCheckbox' templateName: 'MultiCheckbox'
FileCollectionCustomTemplate:
implementationClassName: WerkraumMedia\FormFileCollection\Form\FormElement\FileCollectionElement
renderingOptions:
# Use custom template, ensure it can be found within partialRootPaths
templateName: 'Custom'

View file

@ -0,0 +1,24 @@
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
data-namespace-typo3-fluid="true"
>
<formvh:renderRenderable renderable="{element}">
<f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
<f:for each="{element.properties.files}" as="file" iteration="idIterator">
<f:form.checkbox
property="{element.identifier}"
multiple="1"
id="{element.uniqueIdentifier}-{idIterator.index}"
class="{element.properties.elementClassAttribute}"
value="{file.title}"
errorClass="{element.properties.elementErrorClassAttribute}"
additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
/>
{file.properties.title}
{file.properties.description}
<f:image image="{file}" width="100"/>
</f:for>
</f:render>
</formvh:renderRenderable>
</html>

View file

@ -119,4 +119,21 @@ class FormIntegrationTest extends FunctionalTestCase
self::assertStringContainsString('value="29b827d0daa29658d8a0d952dfd20f559bbe3bcf"', $content); self::assertStringContainsString('value="29b827d0daa29658d8a0d952dfd20f559bbe3bcf"', $content);
self::assertStringContainsString('<span>image/png</span>', $content); self::assertStringContainsString('<span>image/png</span>', $content);
} }
/**
* @test
*/
public function rendersCustomTemplateWithAccessToFiles(): void
{
$this->importPHPDataSet(__DIR__ . '/../Fixtures/CustomTemplate.php');
$request = new InternalRequest();
$request = $request->withPageId(3);
$response = $this->executeFrontendRequest($request);
$content = $response->getBody()->__toString();
self::assertStringContainsString('name="tx_form_formframework[test-3][file-collection-1][]" value="Example title for form"', $content);
self::assertStringContainsString('<img src="/fileadmin/_processed_/2/9/csm_FirstResult_0f8fa1bb68.png" width="100" height="40" alt="Alternative" title="Example title for form" />', $content);
}
} }