mirror of
https://github.com/werkraum-media/form_file_collection.git
synced 2024-12-08 23:36:12 +01:00
parent
10ae3f5783
commit
e635b66d36
25 changed files with 1027 additions and 1 deletions
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
Tests export-ignore
|
||||
.github export-ignore
|
||||
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
|
||||
.php-cs-fixer.dist.php export-ignore
|
||||
phpstan.neon export-ignore
|
||||
phpunit.xml.dist export-ignore
|
||||
|
||||
shell.nix export-ignore
|
144
.github/workflows/ci.yaml
vendored
Normal file
144
.github/workflows/ci.yaml
vendored
Normal file
|
@ -0,0 +1,144 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
check-composer:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: cachix/install-nix-action@v17
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: Validate composer.json
|
||||
run: nix-shell --pure --run project-validate-composer
|
||||
|
||||
php-linting:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-version:
|
||||
- 8.0
|
||||
- 8.1
|
||||
- 8.2
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: PHP lint
|
||||
run: "find *.php Classes Configuration Tests -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l"
|
||||
|
||||
xml-linting:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: cachix/install-nix-action@v17
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: Validate XML
|
||||
run: nix-shell --pure --run project-validate-xml
|
||||
|
||||
coding-guideline:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: cachix/install-nix-action@v17
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: Check Coding Guideline
|
||||
run: nix-shell --pure --run project-coding-guideline
|
||||
|
||||
code-quality:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- php-version: '8.0'
|
||||
typo3-version: '^11.5'
|
||||
- php-version: '8.1'
|
||||
typo3-version: '^11.5'
|
||||
- php-version: '8.2'
|
||||
typo3-version: '^11.5'
|
||||
- php-version: '8.1'
|
||||
typo3-version: '^12.4'
|
||||
- php-version: '8.2'
|
||||
typo3-version: '^12.4'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer req "typo3/cms-core:${{ matrix.typo3-version }}" --prefer-dist --no-progress --no-interaction
|
||||
|
||||
- name: Code Quality (by PHPStan)
|
||||
run: ./vendor/bin/phpstan analyse
|
||||
|
||||
tests-mysql:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- php-version: '8.0'
|
||||
typo3-version: '^11.5'
|
||||
- php-version: '8.1'
|
||||
typo3-version: '^11.5'
|
||||
- php-version: '8.2'
|
||||
typo3-version: '^11.5'
|
||||
- php-version: '8.1'
|
||||
typo3-version: '^12.4'
|
||||
- php-version: '8.2'
|
||||
typo3-version: '^12.4'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "${{ matrix.php-version }}"
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: Setup MySQL
|
||||
uses: mirromutth/mysql-action@v1.1
|
||||
with:
|
||||
mysql version: '8'
|
||||
mysql database: 'typo3'
|
||||
mysql root password: 'root'
|
||||
|
||||
- name: Wait for MySQL
|
||||
run: |
|
||||
while ! mysqladmin ping --host=127.0.0.1 --password=root --silent; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer req "typo3/cms-core:${{ matrix.typo3-version }}" --prefer-dist --no-progress --no-interaction
|
||||
|
||||
- name: PHPUnit Tests
|
||||
env:
|
||||
typo3DatabaseDriver: "pdo_mysql"
|
||||
typo3DatabaseName: "typo3"
|
||||
typo3DatabaseHost: "127.0.0.1"
|
||||
typo3DatabaseUsername: "root"
|
||||
typo3DatabasePassword: "root"
|
||||
run: ./vendor/bin/phpunit --testdox
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/composer.lock
|
||||
/.php-cs-fixer.cache
|
||||
/.Build/
|
||||
/vendor/
|
63
.php-cs-fixer.dist.php
Normal file
63
.php-cs-fixer.dist.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
$finder = (new PhpCsFixer\Finder())
|
||||
->ignoreVCSIgnored(true)
|
||||
->in(realpath(__DIR__));
|
||||
|
||||
return (new \PhpCsFixer\Config())
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
'@DoctrineAnnotation' => true,
|
||||
'@PSR2' => true,
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
'blank_line_after_opening_tag' => true,
|
||||
'braces' => ['allow_single_line_closure' => true],
|
||||
'cast_spaces' => ['space' => 'none'],
|
||||
'compact_nullable_typehint' => true,
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'declare_equal_normalize' => ['space' => 'none'],
|
||||
'dir_constant' => true,
|
||||
'function_to_constant' => ['functions' => ['get_called_class', 'get_class', 'get_class_this', 'php_sapi_name', 'phpversion', 'pi']],
|
||||
'function_typehint_space' => true,
|
||||
'lowercase_cast' => true,
|
||||
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
|
||||
'modernize_strpos' => true,
|
||||
'modernize_types_casting' => true,
|
||||
'native_function_casing' => true,
|
||||
'new_with_braces' => true,
|
||||
'no_alias_functions' => true,
|
||||
'no_blank_lines_after_phpdoc' => true,
|
||||
'no_empty_phpdoc' => true,
|
||||
'no_empty_statement' => true,
|
||||
'no_extra_blank_lines' => true,
|
||||
'no_leading_import_slash' => true,
|
||||
'no_leading_namespace_whitespace' => true,
|
||||
'no_null_property_initialization' => true,
|
||||
'no_short_bool_cast' => true,
|
||||
'no_singleline_whitespace_before_semicolons' => true,
|
||||
'no_superfluous_elseif' => true,
|
||||
'no_trailing_comma_in_singleline_array' => true,
|
||||
'no_unneeded_control_parentheses' => true,
|
||||
'no_unused_imports' => true,
|
||||
'no_useless_else' => true,
|
||||
'no_whitespace_in_blank_line' => true,
|
||||
'ordered_imports' => true,
|
||||
'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']],
|
||||
'php_unit_mock_short_will_return' => true,
|
||||
'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],
|
||||
'phpdoc_no_access' => true,
|
||||
'phpdoc_no_empty_return' => true,
|
||||
'phpdoc_no_package' => true,
|
||||
'phpdoc_scalar' => true,
|
||||
'phpdoc_trim' => true,
|
||||
'phpdoc_separation' => true,
|
||||
'phpdoc_types' => true,
|
||||
'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
|
||||
'return_type_declaration' => ['space_before' => 'none'],
|
||||
'single_quote' => true,
|
||||
'single_line_comment_style' => ['comment_types' => ['hash']],
|
||||
'single_trait_insert_per_statement' => true,
|
||||
'trailing_comma_in_multiline' => ['elements' => ['arrays']],
|
||||
'whitespace_after_comma_in_array' => true,
|
||||
'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false],
|
||||
])
|
||||
->setFinder($finder);
|
97
Classes/Form/FormElement/FileCollectionElement.php
Normal file
97
Classes/Form/FormElement/FileCollectionElement.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 Daniel Siepmann <coding@daniel-siepmann.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
namespace WerkraumMedia\FormFileCollection\Form\FormElement;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileCollectionRepository;
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Form\Domain\Model\FormElements\AbstractFormElement;
|
||||
|
||||
/**
|
||||
* Elements are created with constructor arguments and don't have DI available.
|
||||
*/
|
||||
final class FileCollectionElement extends AbstractFormElement
|
||||
{
|
||||
public function setProperty(string $key, $value): void
|
||||
{
|
||||
if ($key === 'fileCollection' && is_array($value)) {
|
||||
$this->setProperty('options', $this->getOptions($value));
|
||||
return;
|
||||
}
|
||||
|
||||
parent::setProperty($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $configuration
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function getOptions(array $configuration): array
|
||||
{
|
||||
$uid = (int)($configuration['uid'] ?? 0);
|
||||
$collection = $this->getRepository()->findByUid($uid);
|
||||
if ($collection === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (method_exists($collection, 'loadContents')) {
|
||||
$collection->loadContents();
|
||||
}
|
||||
|
||||
$options = [];
|
||||
foreach ($collection->getItems() as $file) {
|
||||
if (!$file instanceof FileInterface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$options = $this->addOption($configuration, $options, $file);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $configuration
|
||||
* @param array<string, string> $options
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private function addOption(
|
||||
array $configuration,
|
||||
array $options,
|
||||
FileInterface $file
|
||||
): array {
|
||||
$value = $file->getProperty($configuration['valueProperty'] ?? 'identifier');
|
||||
$label = $file->getProperty($configuration['labelProperty'] ?? 'identifier');
|
||||
|
||||
$options[$value] = $label;
|
||||
return $options;
|
||||
}
|
||||
|
||||
private function getRepository(): FileCollectionRepository
|
||||
{
|
||||
return GeneralUtility::makeInstance(FileCollectionRepository::class);
|
||||
}
|
||||
}
|
8
Configuration/Form/Setup.yaml
Normal file
8
Configuration/Form/Setup.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
TYPO3:
|
||||
CMS:
|
||||
Form:
|
||||
prototypes:
|
||||
standard:
|
||||
formElementsDefinition:
|
||||
FileCollection:
|
||||
implementationClassName: WerkraumMedia\FormFileCollection\Form\FormElement\FileCollectionElement
|
|
@ -1 +0,0 @@
|
|||
# form_file_collection
|
62
README.rst
Normal file
62
README.rst
Normal file
|
@ -0,0 +1,62 @@
|
|||
====================================
|
||||
TYPO3 Extension Form File Collection
|
||||
====================================
|
||||
|
||||
Adds new EXT:form element used to render a file collection allowing the visitor to choose files.
|
||||
|
||||
Concept
|
||||
=======
|
||||
|
||||
The form element will fetch the configured file collection and assign proper options based on the contained files.
|
||||
That allows using existing templates that allow to select a single or multiple options.
|
||||
|
||||
EXT:form integration
|
||||
====================
|
||||
|
||||
The provided Configuration needs to be loaded via TypoScript.
|
||||
Use a free identifier:
|
||||
|
||||
.. code:: plain
|
||||
|
||||
plugin.tx_form.settings.yamlConfigurations {
|
||||
80 = EXT:form_file_collection/Configuration/Form/Setup.yaml
|
||||
}
|
||||
|
||||
This will register a new form element type ``FileCollection`` that can be used like this:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
-
|
||||
type: FileCollection
|
||||
identifier: file-collection-1
|
||||
label: 'File Collection'
|
||||
properties:
|
||||
fileCollection:
|
||||
# UID of the sys_file_collection to use
|
||||
uid: 1
|
||||
# Optional, default is identifier
|
||||
# Defines the property to use as value for form element.
|
||||
valueProperty: 'identifier'
|
||||
# Optional, default is identifier
|
||||
# Defines the property to use as label for form element.
|
||||
labelProperty: 'identifier'
|
||||
|
||||
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'
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
A concrete example can be found within ``Tests/Fixtures/form_file_collection_example``.
|
66
Tests/Fixtures/BasicDatabase.php
Normal file
66
Tests/Fixtures/BasicDatabase.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'pages' => [
|
||||
[
|
||||
'uid' => 1,
|
||||
'pid' => 0,
|
||||
'slug' => '/',
|
||||
'title' => 'Page Title',
|
||||
],
|
||||
[
|
||||
'uid' => 2,
|
||||
'pid' => 1,
|
||||
'slug' => '/page-2',
|
||||
'title' => 'Page 2 Title',
|
||||
],
|
||||
],
|
||||
'tt_content' => [
|
||||
[
|
||||
'uid' => 1,
|
||||
'pid' => 1,
|
||||
'header' => 'Form',
|
||||
'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/Example.form.yaml</value>
|
||||
</field>
|
||||
<field index="settings.overrideFinishers">
|
||||
<value index="vDEF">0</value>
|
||||
</field>
|
||||
</language>
|
||||
</sheet>
|
||||
</data>
|
||||
</T3FlexForms>
|
||||
',
|
||||
],
|
||||
[
|
||||
'uid' => 2,
|
||||
'pid' => 2,
|
||||
'header' => 'Form',
|
||||
'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/ExampleCustomLabelAndValue.form.yaml</value>
|
||||
</field>
|
||||
<field index="settings.overrideFinishers">
|
||||
<value index="vDEF">0</value>
|
||||
</field>
|
||||
</language>
|
||||
</sheet>
|
||||
</data>
|
||||
</T3FlexForms>
|
||||
',
|
||||
],
|
||||
],
|
||||
];
|
BIN
Tests/Fixtures/Fileadmin/Files/FirstResult.png
Normal file
BIN
Tests/Fixtures/Fileadmin/Files/FirstResult.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
Tests/Fixtures/Fileadmin/Files/SecondResult.png
Normal file
BIN
Tests/Fixtures/Fileadmin/Files/SecondResult.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
5
Tests/Fixtures/Rendering.typoscript
Normal file
5
Tests/Fixtures/Rendering.typoscript
Normal file
|
@ -0,0 +1,5 @@
|
|||
<INCLUDE_TYPOSCRIPT: source="FILE:EXT:fluid_styled_content/Configuration/TypoScript/setup.typoscript">
|
||||
|
||||
page >
|
||||
page = PAGE
|
||||
page.10 =< styles.content.get
|
41
Tests/Fixtures/SingleFileDatabase.php
Normal file
41
Tests/Fixtures/SingleFileDatabase.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'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 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' => 2,
|
||||
],
|
||||
],
|
||||
];
|
32
Tests/Fixtures/Sites/default/config.yaml
Normal file
32
Tests/Fixtures/Sites/default/config.yaml
Normal file
|
@ -0,0 +1,32 @@
|
|||
base: /
|
||||
languages:
|
||||
-
|
||||
title: English
|
||||
enabled: true
|
||||
base: /
|
||||
typo3Language: default
|
||||
locale: en_GB.UTF-8
|
||||
iso-639-1: en
|
||||
websiteTitle: ''
|
||||
navigationTitle: English
|
||||
hreflang: en-GB
|
||||
direction: ''
|
||||
flag: gb
|
||||
languageId: 0
|
||||
fallbackType: strict
|
||||
fallbacks: '0'
|
||||
-
|
||||
title: Deutsch
|
||||
enabled: true
|
||||
base: /de
|
||||
typo3Language: de
|
||||
locale: de_DE.UTF-8
|
||||
iso-639-1: de
|
||||
navigationTitle: Deutsch
|
||||
hreflang: de-DE
|
||||
direction: ''
|
||||
flag: de
|
||||
websiteTitle: ''
|
||||
languageId: 1
|
||||
rootPageId: 1
|
||||
websiteTitle: 'Example Website'
|
66
Tests/Fixtures/TwoFilesDatabase.php
Normal file
66
Tests/Fixtures/TwoFilesDatabase.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'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',
|
||||
],
|
||||
[
|
||||
'uid' => 2,
|
||||
'pid' => 0,
|
||||
'missing' => 0,
|
||||
'storage' => 1,
|
||||
'type' => 2,
|
||||
'metadata' => 0,
|
||||
'identifier' => '/Files/SecondResult.png',
|
||||
'identifier_hash' => '29b827d0daa29658d8a0d952dfd20f559bbe3bcf',
|
||||
'folder_hash' => '86d12d536195df2100a5ec04ab80c08f9bed3d31',
|
||||
'extension' => 'png',
|
||||
'mime_type' => 'image/png',
|
||||
'name' => 'SecondResult.png',
|
||||
'sha1' => 'b13f2bbf275d592534eab659c1430c2702ce31fc',
|
||||
'size' => '42383',
|
||||
],
|
||||
],
|
||||
'sys_file_collection' => [
|
||||
[
|
||||
'uid' => 1,
|
||||
'pid' => 1,
|
||||
'title' => 'Example 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' => 2,
|
||||
],
|
||||
[
|
||||
'uid' => 2,
|
||||
'pid' => 1,
|
||||
'uid_local' => 2,
|
||||
'uid_foreign' => 1,
|
||||
'tablenames' => 'sys_file_collection',
|
||||
'fieldname' => 'files',
|
||||
'sorting_foreign' => 1,
|
||||
],
|
||||
],
|
||||
];
|
|
@ -0,0 +1,34 @@
|
|||
renderingOptions:
|
||||
submitButtonLabel: Submit
|
||||
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: FileCollection
|
||||
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'
|
|
@ -0,0 +1,36 @@
|
|||
renderingOptions:
|
||||
submitButtonLabel: Submit
|
||||
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: FileCollection
|
||||
identifier: file-collection-1
|
||||
label: 'File Collection'
|
||||
properties:
|
||||
fileCollection:
|
||||
uid: 1
|
||||
valueProperty: 'identifier_hash'
|
||||
labelProperty: 'mime_type'
|
||||
-
|
||||
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'
|
|
@ -0,0 +1,14 @@
|
|||
TYPO3:
|
||||
CMS:
|
||||
Form:
|
||||
persistenceManager:
|
||||
allowedExtensionPaths:
|
||||
10: EXT:form_file_collection_example/Configuration/Forms/
|
||||
|
||||
prototypes:
|
||||
standard:
|
||||
formElementsDefinition:
|
||||
FileCollection:
|
||||
renderingOptions:
|
||||
# Allows to switch between different rendering like "Checkbox", "MultiCheckbox" or "RadioButton", etc.
|
||||
templateName: 'MultiCheckbox'
|
|
@ -0,0 +1,6 @@
|
|||
<INCLUDE_TYPOSCRIPT: source="FILE:EXT:form/Configuration/TypoScript/setup.typoscript">
|
||||
|
||||
plugin.tx_form.settings.yamlConfigurations {
|
||||
80 = EXT:form_file_collection/Configuration/Form/Setup.yaml
|
||||
90 = EXT:form_file_collection_example/Configuration/Forms/Setup.yaml
|
||||
}
|
16
Tests/Fixtures/form_file_collection_example/composer.json
Normal file
16
Tests/Fixtures/form_file_collection_example/composer.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "werkraummedia/form-file-collection-example",
|
||||
"description": "Example usage of form file collection",
|
||||
"type": "typo3-cms-extension",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"typo3/cms-core": "*",
|
||||
"typo3/cms-form": "*",
|
||||
"werkraummedia/form-file-collection": "*"
|
||||
},
|
||||
"extra": {
|
||||
"typo3/cms": {
|
||||
"extension-key": "form_file_collection_example"
|
||||
}
|
||||
}
|
||||
}
|
122
Tests/Functional/FormIntegrationTest.php
Normal file
122
Tests/Functional/FormIntegrationTest.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Copyright (C) 2023 Daniel Siepmann <coding@daniel-siepmann.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
namespace WerkraumMedia\FormFileCollection\Tests\Functional;
|
||||
|
||||
use Codappix\Typo3PhpDatasets\TestingFramework;
|
||||
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
|
||||
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
|
||||
|
||||
class FormIntegrationTest extends FunctionalTestCase
|
||||
{
|
||||
use TestingFramework;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->coreExtensionsToLoad = [
|
||||
'fluid_styled_content',
|
||||
'form',
|
||||
];
|
||||
$this->testExtensionsToLoad = [
|
||||
'typo3conf/ext/form_file_collection',
|
||||
'typo3conf/ext/form_file_collection/Tests/Fixtures/form_file_collection_example',
|
||||
];
|
||||
$this->pathsToLinkInTestInstance = [
|
||||
'typo3conf/ext/form_file_collection/Tests/Fixtures/Sites' => 'typo3conf/sites',
|
||||
'typo3conf/ext/form_file_collection/Tests/Fixtures/Fileadmin/Files' => 'fileadmin/Files',
|
||||
];
|
||||
|
||||
parent::setUp();
|
||||
|
||||
$this->importPHPDataSet(__DIR__ . '/../Fixtures/BasicDatabase.php');
|
||||
$this->setUpFrontendRootPage(1, [
|
||||
'setup' => [
|
||||
'EXT:form_file_collection/Tests/Fixtures/Rendering.typoscript',
|
||||
'EXT:form_file_collection_example/Configuration/TypoScript/Form.typoscript',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function rendersFileFromSelectedCollection(): void
|
||||
{
|
||||
$this->importPHPDataSet(__DIR__ . '/../Fixtures/SingleFileDatabase.php');
|
||||
|
||||
$request = new InternalRequest();
|
||||
|
||||
$response = $this->executeFrontendRequest($request);
|
||||
|
||||
$content = $response->getBody()->__toString();
|
||||
self::assertStringContainsString('name="tx_form_formframework[test-1][file-collection-1]"', $content);
|
||||
|
||||
self::assertStringContainsString('FirstResult.png', $content);
|
||||
self::assertStringContainsString('value="/Files/FirstResult.png"', $content);
|
||||
self::assertStringContainsString('<span>/Files/FirstResult.png</span>', $content);
|
||||
|
||||
self::assertStringNotContainsString('SecondResult.png', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function providesMultipleFilesFromSelectedCollection(): void
|
||||
{
|
||||
$this->importPHPDataSet(__DIR__ . '/../Fixtures/TwoFilesDatabase.php');
|
||||
|
||||
$request = new InternalRequest();
|
||||
|
||||
$response = $this->executeFrontendRequest($request);
|
||||
|
||||
$content = $response->getBody()->__toString();
|
||||
self::assertStringContainsString('name="tx_form_formframework[test-1][file-collection-1][]"', $content);
|
||||
|
||||
self::assertStringContainsString('FirstResult.png', $content);
|
||||
self::assertStringContainsString('value="/Files/FirstResult.png"', $content);
|
||||
self::assertStringContainsString('<span>/Files/FirstResult.png</span>', $content);
|
||||
|
||||
self::assertStringContainsString('SecondResult.png', $content);
|
||||
self::assertStringContainsString('value="/Files/SecondResult.png"', $content);
|
||||
self::assertStringContainsString('<span>/Files/SecondResult.png</span>', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function rendersConfiguredLabel(): void
|
||||
{
|
||||
$this->importPHPDataSet(__DIR__ . '/../Fixtures/SingleFileDatabase.php');
|
||||
|
||||
$request = new InternalRequest();
|
||||
$request = $request->withPageId(2);
|
||||
|
||||
$response = $this->executeFrontendRequest($request);
|
||||
|
||||
$content = $response->getBody()->__toString();
|
||||
self::assertStringContainsString('name="tx_form_formframework[test-2][file-collection-1][]"', $content);
|
||||
|
||||
self::assertStringContainsString('value="29b827d0daa29658d8a0d952dfd20f559bbe3bcf"', $content);
|
||||
self::assertStringContainsString('<span>image/png</span>', $content);
|
||||
}
|
||||
}
|
68
composer.json
Normal file
68
composer.json
Normal file
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"name": "werkraummedia/form-file-collection",
|
||||
"description": "Add a form element to render file collection to EXT:form of TYPO3",
|
||||
"type": "typo3-cms-extension",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"homepage": "https://github.com/werkraum-media/form_file_collection",
|
||||
"support": {
|
||||
"docs": "https://docs.typo3.org/p/werkraummedia/form_file_collection/master/en-us/",
|
||||
"email": "coding@daniel-siepmann.de",
|
||||
"issues": "https://github.com/werkraum-media/form_file_collection/issues",
|
||||
"source": "https://github.com/werkraum-media/form_file_collection"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Daniel Siepmann",
|
||||
"email": "coding@daniel-siepmann.de",
|
||||
"homepage": "https://daniel-siepmann.de/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"WerkraumMedia\\FormFileCollection\\": "Classes/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"WerkraumMedia\\FormFileCollection\\Tests\\": "Tests/",
|
||||
"WerkraumMedia\\FormFileCollectionExample\\": "Tests/Fixtures/form_file_collection_example/Classes/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": "~8.0.0 || ~8.1.0 || ~8.2.0",
|
||||
"typo3/cms-backend": "^11.5 || ^12.4",
|
||||
"typo3/cms-core": "^11.5 || ^12.4",
|
||||
"typo3/cms-fluid-styled-content": "^11.5 || ^12.4",
|
||||
"typo3/cms-form": "^11.5 || ^12.4",
|
||||
"typo3/cms-frontend": "^11.5 || ^12.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"codappix/typo3-php-datasets": "^1.3",
|
||||
"friendsofphp/php-cs-fixer": "^3.11",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"saschaegerer/phpstan-typo3": "^1.8",
|
||||
"typo3/testing-framework": "^7.0"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"lock": false,
|
||||
"allow-plugins": {
|
||||
"typo3/cms-composer-installers": true,
|
||||
"typo3/class-alias-loader": true,
|
||||
"ocramius/package-versions": true,
|
||||
"phpstan/extension-installer": true,
|
||||
"cweagans/composer-patches": true
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"typo3/cms": {
|
||||
"app-dir": ".Build",
|
||||
"extension-key": "form_file_collection",
|
||||
"web-dir": ".Build/web"
|
||||
}
|
||||
}
|
||||
}
|
6
phpstan.neon
Normal file
6
phpstan.neon
Normal file
|
@ -0,0 +1,6 @@
|
|||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- Classes
|
||||
- Tests
|
||||
reportUnmatchedIgnoredErrors: true
|
35
phpunit.xml.dist
Normal file
35
phpunit.xml.dist
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0"?>
|
||||
<phpunit
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTestsBootstrap.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
forceCoversAnnotation="false"
|
||||
processIsolation="false"
|
||||
stopOnError="false"
|
||||
stopOnFailure="false"
|
||||
stopOnIncomplete="false"
|
||||
stopOnSkipped="false"
|
||||
verbose="false"
|
||||
>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="functional">
|
||||
<directory>Tests/Functional/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<coverage>
|
||||
<include>
|
||||
<directory suffix=".php">Classes</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
|
||||
<php>
|
||||
<env name="typo3DatabaseDriver" value="pdo_sqlite"/>
|
||||
</php>
|
||||
</phpunit>
|
91
shell.nix
Normal file
91
shell.nix
Normal file
|
@ -0,0 +1,91 @@
|
|||
{
|
||||
pkgs ? import <nixpkgs> { }
|
||||
}:
|
||||
|
||||
let
|
||||
php = pkgs.php82.buildEnv {
|
||||
extensions = { enabled, all }: enabled ++ (with all; [
|
||||
xdebug
|
||||
]);
|
||||
|
||||
extraConfig = ''
|
||||
xdebug.mode = debug
|
||||
memory_limit = 4G
|
||||
'';
|
||||
};
|
||||
inherit(php.packages) composer;
|
||||
|
||||
projectInstall = pkgs.writeShellApplication {
|
||||
name = "project-install";
|
||||
runtimeInputs = [
|
||||
php
|
||||
composer
|
||||
];
|
||||
text = ''
|
||||
rm -rf .Build/ vendor/
|
||||
composer install --prefer-dist --no-progress --working-dir="$PROJECT_ROOT"
|
||||
'';
|
||||
};
|
||||
projectValidateComposer = pkgs.writeShellApplication {
|
||||
name = "project-validate-composer";
|
||||
runtimeInputs = [
|
||||
php
|
||||
composer
|
||||
];
|
||||
text = ''
|
||||
composer validate
|
||||
'';
|
||||
};
|
||||
projectValidateXml = pkgs.writeShellApplication {
|
||||
name = "project-validate-xml";
|
||||
runtimeInputs = [
|
||||
pkgs.libxml2
|
||||
pkgs.wget
|
||||
projectInstall
|
||||
];
|
||||
text = ''
|
||||
project-install
|
||||
xmllint --schema vendor/phpunit/phpunit/phpunit.xsd --noout phpunit.xml.dist
|
||||
'';
|
||||
};
|
||||
projectCodingGuideline = pkgs.writeShellApplication {
|
||||
name = "project-coding-guideline";
|
||||
runtimeInputs = [
|
||||
php
|
||||
projectInstall
|
||||
];
|
||||
text = ''
|
||||
project-install
|
||||
./vendor/bin/php-cs-fixer fix --dry-run --diff
|
||||
'';
|
||||
};
|
||||
projectCodingGuidelineFix = pkgs.writeShellApplication {
|
||||
name = "project-coding-guideline-fix";
|
||||
runtimeInputs = [
|
||||
php
|
||||
projectInstall
|
||||
];
|
||||
text = ''
|
||||
project-install
|
||||
./vendor/bin/php-cs-fixer fix
|
||||
'';
|
||||
};
|
||||
|
||||
in pkgs.mkShell {
|
||||
name = "TYPO3 Extension FormFileCollection";
|
||||
buildInputs = [
|
||||
projectInstall
|
||||
projectValidateComposer
|
||||
projectValidateXml
|
||||
projectCodingGuideline
|
||||
projectCodingGuidelineFix
|
||||
php
|
||||
composer
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
export PROJECT_ROOT="$(pwd)"
|
||||
|
||||
export typo3DatabaseDriver=pdo_sqlite
|
||||
'';
|
||||
}
|
Loading…
Reference in a new issue