diff --git a/.check-author.yml b/.check-author.yml deleted file mode 100644 index f266ac9..0000000 --- a/.check-author.yml +++ /dev/null @@ -1,16 +0,0 @@ -ignore: - - 'Mini Model ' - -exclude: - - /^src\/Resources\/contao\/languages/ - -mapping: - 'Andreas Isaak ': 'Andreas Isaak ' - 'Christopher Boelter ': - - 'cogizz ' - - 'cboelter ' - - 'Christopher Boelter ' - 'Ingolf Steinhardt ': - - 'zonky2 ' - - 'Ingolf Steinhardt ' - - 'Ingolf Steinhardt ' diff --git a/.composer-require-checker.json b/.composer-require-checker.json new file mode 100644 index 0000000..1fbb404 --- /dev/null +++ b/.composer-require-checker.json @@ -0,0 +1,17 @@ +{ + "symbol-whitelist": [ + "array", "bool", "false", "int", "null", "self", "static", "parent", "string", "true", "void", "mixed", + "Contao\\ManagerBundle\\ContaoManagerBundle", + "Contao\\ManagerPlugin\\Bundle\\BundlePluginInterface", + "Contao\\ManagerPlugin\\Bundle\\Config\\BundleConfig", + "Contao\\ManagerPlugin\\Bundle\\Parser\\ParserInterface", + "Contao\\ManagerPlugin\\Routing\\RoutingPluginInterface", + "MetaModels\\ContaoFrontendEditingBundle\\MetaModelsContaoFrontendEditingBundle", + "InspiredMinds\\ContaoFileUsage\\ContaoFileUsageBundle", + "InspiredMinds\\ContaoFileUsage\\Provider\\FileUsageProviderInterface", + "InspiredMinds\\ContaoFileUsage\\Result\\FileTreeMultipleResult", + "InspiredMinds\\ContaoFileUsage\\Result\\FileTreeSingleResult", + "InspiredMinds\\ContaoFileUsage\\Result\\ResultInterface", + "InspiredMinds\\ContaoFileUsage\\Result\\ResultsCollection" + ] +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..273e702 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 +updates: +- package-ecosystem: composer + directory: "/" + schedule: + interval: daily + time: "04:00" + timezone: Europe/Berlin + open-pull-requests-limit: 10 diff --git a/.github/workflows/diagnostics.yml b/.github/workflows/diagnostics.yml index 218a32c..9d4510b 100644 --- a/.github/workflows/diagnostics.yml +++ b/.github/workflows/diagnostics.yml @@ -1,52 +1,75 @@ name: MetaModels attribute_file on: - push: - branches-ignore: - - '**-translation' pull_request: + push: + branches: jobs: build: runs-on: ubuntu-latest + name: 'PHP: ${{ matrix.php }} Contao: ${{ matrix.contao }}' strategy: + fail-fast: false matrix: - php: [7.4] - contao: [~4.9.0] + php: [ '8.1', '8.2', '8.3' ] + contao: [ '~4.13.0' ] + phpcq_install: [ 'update' ] + output: [ '-o github-action -o default' ] steps: - - name: PHP ${{ matrix.php }} ${{ matrix.contao }} Pull source - uses: actions/checkout@v3 - with: - fetch-depth: 0 + - name: Pull source + uses: actions/checkout@v4 - # see https://github.com/shivammathur/setup-php - - name: PHP ${{ matrix.php }} ${{ matrix.contao }} Setup PHP. + - name: Setup PHP with PECL extension uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - coverage: none - - name: PHP ${{ matrix.php }} ${{ matrix.contao }} Cache composer cache directory - uses: actions/cache@v3 + # setup caches + - name: Cache composer cache directory + uses: actions/cache@v4 env: cache-name: composer-cache-dir with: path: ~/.cache/composer - key: ${{ runner.os }}-build-${{ env.cache-name }} + key: ${{ runner.os }}-${{ matrix.php }}-build-${{ env.cache-name }} - - name: PHP ${{ matrix.php }} ${{ matrix.contao }} Cache vendor directory - uses: actions/cache@v3 + - name: Cache vendor directory + uses: actions/cache@v4 env: - cache-name: composer-vendor + cache-name: vendor with: path: vendor - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/composer.lock') }} + key: ${{ runner.os }}-${{ matrix.php }}-${{ matrix.contao }}-build-${{ env.cache-name }}-${{ hashFiles('**/composer.lock') }} restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-${{ matrix.php }}-${{ matrix.contao }}-build-${{ env.cache-name }}- - - name: PHP ${{ matrix.php }} ${{ matrix.contao }} Install composer dependencies - run: composer update --prefer-dist --no-interaction --no-suggest + - name: Cache phpcq directory + uses: actions/cache@v4 + env: + cache-name: phpcq + with: + path: .phpcq + key: ${{ runner.os }}-${{ matrix.php }}-build-${{ env.cache-name }}-${{ hashFiles('**/.phpcq.lock') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.php }}-build-${{ env.cache-name }}- + + # install dependencies and tools + - name: Install composer dependencies + run: | + composer require contao/core-bundle ${{ matrix.contao }} --no-update + composer install + - name: Install phpcq toolchain + run: ./vendor/bin/phpcq ${{ matrix.phpcq_install }} -v - - name: PHP ${{ matrix.php }} ${{ matrix.contao }} Run tests - run: ant -keep-going + # run tests + - name: Run tests + run: ./vendor/bin/phpcq run -v ${{ matrix.output }} + + - name: Upload build directory to artifact + uses: actions/upload-artifact@v4 + if: ${{ success() }} || ${{ failure() }} + with: + name: phpcq-builds-php-${{ matrix.php }}-${{ matrix.contao }} + path: .phpcq/build/ diff --git a/.gitignore b/.gitignore index 3707056..eccdc19 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ Thumbs.db .build/ .external*/ .idea/ +.phpcq/ nbproject/ # composer related diff --git a/.phpcq.lock b/.phpcq.lock new file mode 100644 index 0000000..f19c1f3 --- /dev/null +++ b/.phpcq.lock @@ -0,0 +1 @@ +{"plugins":{"phpunit":{"api-version":"1.0.0","version":"1.0.0.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/phpunit/phpunit-1.0.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0"},"tool":{"phpunit":"^6.0 || ^7.0 || ^8.0 || ^9.0"}},"checksum":{"type":"sha-512","value":"c73f15658e3ba62665f09492ec91c3a6a715760bfaa88473a987538439fff442540148e086e46a6aa18ce55a3ea2fbf76caaa581384cb84a38859fcc609ae7e4"},"tools":{"phpunit":{"version":"9.6.22","url":"https://phar.phpunit.de/phpunit-9.6.22.phar","requirements":{"php":{"php":">=7.3","ext-dom":"*","ext-json":"*","ext-libxml":"*","ext-mbstring":"*","ext-xml":"*","ext-xmlwriter":"*"}},"checksum":{"type":"sha-256","value":"9618d52015c9b06b4979a8e481ca9567be6be20e711e98926c61378a400e1f2e"},"signature":"https://phar.phpunit.de/phpunit-9.6.22.phar.asc"}},"composerLock":null},"psalm":{"api-version":"1.0.0","version":"1.3.0.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/psalm/psalm-1.3.0.0.php","signature":null,"requirements":{"php":{"php":"^7.4 || ^8.0","ext-dom":"*"},"tool":{"psalm":"^3.0 || ^4.0 || ^5.0 || ^6.0"}},"checksum":{"type":"sha-512","value":"4a550c9226d7bca582d7c10bd87cce01190c96398936b1613421640c83df62ed1c6e0d44c1b39635414ea8cf4a892a6458d27590793238add24e7cb5547e6ffd"},"tools":{"psalm":{"version":"5.26.1","url":"https://github.com/vimeo/psalm/releases/download/5.26.1/psalm.phar","requirements":{"php":{"php":"^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0","ext-SimpleXML":"*","ext-ctype":"*","ext-dom":"*","ext-json":"*","ext-libxml":"*","ext-mbstring":"*","ext-tokenizer":"*"}},"checksum":null,"signature":"https://github.com/vimeo/psalm/releases/download/5.26.1/psalm.phar.asc"}},"composerLock":null},"composer-require-checker":{"api-version":"1.0.0","version":"1.1.1.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/composer-require-checker/composer-require-checker-1.1.1.0.php","signature":null,"requirements":{"php":{"php":"^7.4 || ^8.0"},"tool":{"composer-require-checker":"^3.8 || ^4.0"}},"checksum":{"type":"sha-512","value":"d5415bddfe024c5749d894034583882aee4e5c3e1087815d9fdd81cb5e71630f631a0e35de0ff84b97fbbf738c16ece5f83bd8c00695913eb846aa6f04577dc2"},"tools":{"composer-require-checker":{"version":"4.7.1","url":"https://github.com/maglnet/ComposerRequireChecker/releases/download/4.7.1/composer-require-checker.phar","requirements":{"php":{"php":"~8.1.0 || ~8.2.0 || ~8.3.0","ext-phar":"*"}},"checksum":null,"signature":"https://github.com/maglnet/ComposerRequireChecker/releases/download/4.7.1/composer-require-checker.phar.asc"}},"composerLock":null},"phpmd":{"api-version":"1.0.0","version":"1.0.2.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/phpmd/phpmd-1.0.2.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"phpmd":"^2.6.1"}},"checksum":{"type":"sha-512","value":"f22280a6dec8dbdd2ec1d83b294f23237fe32c34f4a298e52038e0a7a0074d541635b2b488b1a6098a42d8418a6cd8eb804406ea82b91e362be2b5d11a0915b0"},"tools":{"phpmd":{"version":"2.15.0","url":"https://github.com/phpmd/phpmd/releases/download/2.15.0/phpmd.phar","requirements":{"php":{"php":">=5.3.9","ext-xml":"*"}},"checksum":null,"signature":"https://github.com/phpmd/phpmd/releases/download/2.15.0/phpmd.phar.asc"}},"composerLock":null},"phpcpd":{"api-version":"1.0.0","version":"1.1.1.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/phpcpd/phpcpd-1.1.1.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"phpcpd":"^6.0"}},"checksum":{"type":"sha-512","value":"1189ce0bf3fade4cb4241f1d96f915ef8fc7651f4450dc79fdf464ee3d6be3009316f0d423ce2d4af9d76ad50807b7fdf4d77bfa6d9ee2c91d6eda32ea214433"},"tools":{"phpcpd":{"version":"6.0.3","url":"https://phar.phpunit.de/phpcpd-6.0.3.phar","requirements":{"php":{"php":">=7.3","ext-dom":"*"}},"checksum":{"type":"sha-256","value":"2cbaea7cfda1bb4299d863eb075e977c3f49055dd16d88529fae5150d48a84cb"},"signature":"https://phar.phpunit.de/phpcpd-6.0.3.phar.asc"}},"composerLock":null},"phploc":{"api-version":"1.0.0","version":"1.0.0.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/phploc/phploc-1.0.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*","ext-json":"*"},"tool":{"phploc":"^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0"}},"checksum":{"type":"sha-512","value":"f67b02d494796adf553cb3dd13ec06c1cb8e53c799954061749424251379541637538199afb3afa3c7a01cabd1cb6f1c53eb621f015dff9644c6c7cbf10c56d1"},"tools":{"phploc":{"version":"7.0.2","url":"https://phar.phpunit.de/phploc-7.0.2.phar","requirements":{"php":{"php":">=7.3","ext-dom":"*","ext-json":"*"}},"checksum":{"type":"sha-256","value":"3d59778ec86faf25fd00e3a329b2f9ad4a3c751ca91601ea7dab70f887b0bf46"},"signature":"https://phar.phpunit.de/phploc-7.0.2.phar.asc"}},"composerLock":null},"phpcs":{"api-version":"1.0.0","version":"1.2.0.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/phpcs/phpcs-1.2.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"phpcs":"^3.0 || ^2.0","phpcbf":"^3.0 || ^2.0"}},"checksum":{"type":"sha-512","value":"b6ed00306e76068a6af5e3b1dec837724f9e1900ef1049ce88e7ce195b0583524ca33a73613fba13244307a7ca853b6ddaa14ded69f651c3f184ac130bd1aaad"},"tools":{"phpcs":{"version":"3.12.0","url":"https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/download/3.12.0/phpcs.phar","requirements":{"php":{"php":">=5.4.0","ext-simplexml":"*","ext-tokenizer":"*","ext-xmlwriter":"*"}},"checksum":null,"signature":"https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/download/3.12.0/phpcs.phar.asc"},"phpcbf":{"version":"3.12.0","url":"https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/download/3.12.0/phpcbf.phar","requirements":{"php":{"php":">=5.4.0","ext-simplexml":"*","ext-tokenizer":"*","ext-xmlwriter":"*"}},"checksum":null,"signature":"https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/download/3.12.0/phpcbf.phar.asc"}},"composerLock":null},"composer-normalize":{"api-version":"1.0.0","version":"1.1.1.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/composer-normalize/composer-normalize-1.1.1.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-json":"*"},"tool":{"composer-normalize":"^2.1"}},"checksum":{"type":"sha-512","value":"d9abda440b85d501c58abf9c81bf76f417594b397129215ffa8b777e9bb5e5eda37d7661d661db3c8d11c24f20345bc6fbe56f013b3b9435d459d2b94f086e0f"},"tools":{"composer-normalize":{"version":"2.45.0","url":"https://github.com/ergebnis/composer-normalize/releases/download/2.45.0/composer-normalize.phar","requirements":{"php":{"php":"~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0","ext-json":"*"}},"checksum":null,"signature":"https://github.com/ergebnis/composer-normalize/releases/download/2.45.0/composer-normalize.phar.asc"}},"composerLock":null}},"tools":[]} \ No newline at end of file diff --git a/.phpcq.yaml.dist b/.phpcq.yaml.dist new file mode 100644 index 0000000..a0ff982 --- /dev/null +++ b/.phpcq.yaml.dist @@ -0,0 +1,117 @@ +phpcq: + repositories: + - https://phpcq.github.io/repository/repository.json + directories: + - src + - tests + artifact: .phpcq/build + composer: + autodiscover: false + + plugins: + phpunit: + version: ^1.0 + signed: false + psalm: + version: ^1.0 + signed: false + requirements: + psalm: + version: ^5.26.1 + composer-require-checker: + version: ^1.0 + signed: false + phpmd: + version: ^1.0 + signed: false + phpcpd: + version: ^1.1 + signed: false + phploc: + version: ^1.0 + signed: false + phpcs: + version: ^1.0 + signed: false + composer-normalize: + version: ^1.0 + signed: false + trusted-keys: + # composer-require-checker + - 033E5F8D801A2F8D + # sb@sebastian-bergmann.de + - 4AA394086372C20A + # psalm + - 8A03EA3B385DBAA1 + - 12CE0F1D262429A5 + # magl@magll.net + - D2CCAC42F6295E7D + # PHP_CodeSniffer + - 31C7E470E2138192 + - 5E6DDE998AB73B8E + - A978220305CD5C32 + # Composer normalize + - C00543248C87FB13 + # phpmd + - A4E55EA12C7C085C + - 9093F8B32E4815AA + +tasks: + fix: + - composer-normalize-fix + - phpcbf + + verify: + - composer-require-checker + - composer-normalize + + analyze: + - phploc + - phpcpd + - phpmd + - phpcs + - psalm + - phpunit + + default: + - verify + - analyze + + phpcpd: + plugin: phpcpd + config: + exclude: + - tests + - src/EventListener/DcGeneral/Table/DcaSetting/FeeFileImageSizeOptions.php + - src/EventListener/DcGeneral/Table/RenderSetting/FileImageSizeOptions.php + + phpmd: + plugin: phpmd + config: + ruleset: + - ./.phpmd.xml + + composer-require-checker: + plugin: composer-require-checker + config: + config_file: '.composer-require-checker.json' + + phpcs: + plugin: phpcs + config: &phpcs-config + standard: PSR12 + excluded: + - '*/Resources/contao/dca/*' + - '*/Resources/contao/languages/*' + - '*/Resources/public/*' + + phpcbf: + plugin: phpcs + config: + <<: *phpcs-config + fix: true + + composer-normalize-fix: + plugin: composer-normalize + config: + dry_run: false diff --git a/.phpmd.xml b/.phpmd.xml new file mode 100644 index 0000000..78eb716 --- /dev/null +++ b/.phpmd.xml @@ -0,0 +1,37 @@ + + + + PHPMD rule set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.tx/config b/.tx/config new file mode 100644 index 0000000..6a1f87a --- /dev/null +++ b/.tx/config @@ -0,0 +1,29 @@ +[main] +host = https://app.transifex.com + +[o:metamodels:p:attribute-file:r:tl_metamodel_attribute] +file_filter = src/Resources/translations/tl_metamodel_attribute..xlf +source_file = src/Resources/translations/tl_metamodel_attribute.en.xlf +type = XLIFF +minimum_perc = 0 +resource_name = tl_metamodel_attribute +replace_edited_strings = false +keep_translations = false + +[o:metamodels:p:attribute-file:r:tl_metamodel_dcasetting] +file_filter = src/Resources/translations/tl_metamodel_dcasetting..xlf +source_file = src/Resources/translations/tl_metamodel_dcasetting.en.xlf +type = XLIFF +minimum_perc = 0 +resource_name = tl_metamodel_dcasetting +replace_edited_strings = false +keep_translations = false + +[o:metamodels:p:attribute-file:r:tl_metamodel_rendersetting] +file_filter = src/Resources/translations/tl_metamodel_rendersetting..xlf +source_file = src/Resources/translations/tl_metamodel_rendersetting.en.xlf +type = XLIFF +minimum_perc = 0 +resource_name = tl_metamodel_rendersetting +replace_edited_strings = false +keep_translations = false diff --git a/build.default.properties b/build.default.properties deleted file mode 100644 index 422e9db..0000000 --- a/build.default.properties +++ /dev/null @@ -1,12 +0,0 @@ -##################################################### -## This project is using the ## -## PHP code quality project (phpcq) ## -## ## -## https://github.com/phpcq/phpcq ## -##################################################### - -phpcs.standard=${basedir}/vendor/phpcq/coding-standard/phpcs/PhpCodeQuality/ruleset.xml -phpmd.ruleset=${basedir}/vendor/phpcq/coding-standard/phpmd/ruleset.xml - -phpcs.excluded=src/Resources/contao/languages*\ - ,src/Resources/contao/dca* diff --git a/build.xml b/build.xml deleted file mode 100644 index 2b34341..0000000 --- a/build.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - diff --git a/composer.json b/composer.json index 88edefd..ec2aa94 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,8 @@ { "name": "metamodels/attribute_file", "description": "MetaModels attribute for files", + "license": "LGPL-3.0-or-later", + "type": "contao-bundle", "keywords": [ "contao", "metamodels", @@ -8,9 +10,6 @@ "file", "nontranslatable" ], - "type": "contao-bundle", - "homepage": "https://now.metamodel.me/", - "license": "LGPL-3.0-or-later", "authors": [ { "name": "Christian Schiffler", @@ -24,31 +23,34 @@ "role": "Developer" } ], + "homepage": "https://now.metamodel.me/", "support": { "email": "mail@metamodel.me", "issues": "https://github.com/MetaModels/attribute_file/issues", "wiki": "https://de.contaowiki.org/MetaModels", - "irc": "irc://irc.freenode.org/contao.mm", "source": "https://github.com/MetaModels/attribute_file" }, "require": { - "php": "^7.4", - "ext-pdo": "*", - "cache/array-adapter": "^1.0", - "cache/doctrine-adapter": "^1.0", - "contao-community-alliance/dc-general": "^2.2", - "contao/core-bundle": "^4.9.0, <4.13.0", - "metamodels/core": "^2.2", - "psr/simple-cache": "^1.0", - "symfony/dependency-injection": "^4.4.6", - "symfony/event-dispatcher": "^4.4.6", - "symfony/http-kernel": "~4.4.13" + "php": "^8.1", + "contao-community-alliance/dc-general": "^2.3", + "contao/core-bundle": "^4.13.0 <5.0", + "doctrine/dbal": "^3.6.0", + "metamodels/core": "^2.3", + "symfony/cache": "^5.4", + "symfony/config": "^5.4", + "symfony/dependency-injection": "^5.4", + "symfony/http-foundation": "^5.4", + "symfony/http-kernel": "^5.4", + "symfony/routing": "^5.4", + "symfony/security-core": "^5.4", + "symfony/translation-contracts": "^2.5.2" }, "require-dev": { "contao/manager-plugin": "^2.1", - "metamodels/contao-frontend-editing": "^2.1", + "inspiredminds/contao-file-usage": "^3.0.1", "menatwork/contao-multicolumnwizard-bundle": "^3.4", - "phpcq/all-tasks": "^1.2" + "metamodels/contao-frontend-editing": "^2.3", + "phpcq/runner-bootstrap": "^1.0@dev" }, "autoload": { "psr-4": { @@ -63,14 +65,18 @@ "MetaModels\\AttributeFileBundle\\Test\\": "tests" } }, - "extra": { - "contao-manager-plugin": "MetaModels\\AttributeFileBundle\\ContaoManager\\Plugin" - }, "config": { "allow-plugins": { "contao-components/installer": false, - "contao/manager-plugin": false + "contao/manager-plugin": false, + "php-http/discovery": true }, "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-feature/2.3.0": "2.3.x-dev" + }, + "contao-manager-plugin": "MetaModels\\AttributeFileBundle\\ContaoManager\\Plugin" } } diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..663fb43 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/src/Attribute/AttributeOrderTypeFactory.php b/src/Attribute/AttributeOrderTypeFactory.php index 06ccb9d..3cb7599 100644 --- a/src/Attribute/AttributeOrderTypeFactory.php +++ b/src/Attribute/AttributeOrderTypeFactory.php @@ -86,14 +86,14 @@ public function getTypeIcon() */ public function createInstance($information, $metaModel) { - $columnName = ($information['colname'] ?? null); + $columnName = (string) ($information['colname'] ?? ''); $tableName = $metaModel->getTableName(); if (!isset($this->tableColumns[$tableName])) { - $this->tableColumns[$tableName] = $this->connection->getSchemaManager()->listTableColumns($tableName); + $this->tableColumns[$tableName] = $this->connection->createSchemaManager()->listTableColumns($tableName); } - if (!$columnName || !\array_key_exists($columnName, $this->tableColumns[$tableName])) { + if (('' === $columnName) || !\array_key_exists($columnName, $this->tableColumns[$tableName])) { return null; } diff --git a/src/Attribute/AttributeTypeFactory.php b/src/Attribute/AttributeTypeFactory.php index 795ec16..4f35ee0 100644 --- a/src/Attribute/AttributeTypeFactory.php +++ b/src/Attribute/AttributeTypeFactory.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2019 The MetaModels team. + * (c) 2012-2024 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -14,7 +14,8 @@ * @author Christian Schiffler * @author Sven Baumann * @author Stefan Heimes - * @copyright 2012-2019 The MetaModels team. + * @author Ingolf Steinhardt + * @copyright 2012-2024 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -23,7 +24,6 @@ use Contao\Config; use Contao\CoreBundle\Framework\Adapter; -use Contao\CoreBundle\Image\ImageFactoryInterface; use Contao\FilesModel; use Contao\StringUtil; use Doctrine\DBAL\Connection; @@ -56,46 +56,46 @@ class AttributeTypeFactory implements IAttributeTypeFactory * * @var ToolboxFile */ - private $toolboxFile; + private ToolboxFile $toolboxFile; /** * The string util. * - * @var Adapter|StringUtil + * @var Adapter */ - private $stringUtil; + private Adapter $stringUtil; /** * The validator. * - * @var Adapter|Validator + * @var Adapter */ - private $validator; + private Adapter $validator; /** * The repository for files. * - * @var Adapter|FilesModel + * @var Adapter */ - private $fileRepository; + private Adapter $fileRepository; /** * The contao configurations. * - * @var Adapter|Config + * @var Adapter */ - private $config; + private Adapter $config; /** * {@inheritDoc} * - * @param Connection $connection The database connection. - * @param TableManipulator $tableManipulator The table manipulator. - * @param ToolboxFile $toolboxFile The toolbox for file. - * @param Adapter|StringUtil $stringUtil The string util. - * @param Adapter|Validator $validator The validator. - * @param Adapter|FilesModel $fileRepository The repository for files. - * @param Adapter|Config $config The contao configurations. + * @param Connection $connection The database connection. + * @param TableManipulator $tableManipulator The table manipulator. + * @param ToolboxFile $toolboxFile The toolbox for file. + * @param Adapter $stringUtil The string util. + * @param Adapter $validator The validator. + * @param Adapter $fileRepository The repository for files. + * @param Adapter $config The contao configurations. */ public function __construct( Connection $connection, diff --git a/src/Attribute/File.php b/src/Attribute/File.php index 4ed890b..a3bdb6f 100644 --- a/src/Attribute/File.php +++ b/src/Attribute/File.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2022 The MetaModels team. + * (c) 2012-2024 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -23,7 +23,7 @@ * @author David Molineus * @author Sven Baumann * @author Ingolf Steinhardt - * @copyright 2012-2022 The MetaModels team. + * @copyright 2012-2024 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -36,80 +36,97 @@ use Contao\StringUtil; use Contao\System; use Contao\Validator; +use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Platforms\Keywords\KeywordList; use MetaModels\Attribute\BaseComplex; +use MetaModels\Attribute\ManagedAttributeTrait; use MetaModels\Helper\TableManipulator; use MetaModels\Helper\ToolboxFile; use MetaModels\IMetaModel; use MetaModels\Render\Template; +use function array_key_exists; +use function array_map; +use function array_merge; +use function array_values; +use function is_array; +use function serialize; +use function sprintf; +use function str_replace; +use function trigger_error; +use function trim; + /** * This is the MetaModel attribute class for handling file fields. + * + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class File extends BaseComplex { + use ManagedAttributeTrait; + /** * The database connection. * - * @var Connection|null + * @var Connection */ - private $connection; + private Connection $connection; /** * Table manipulator instance. * - * @var TableManipulator|null + * @var TableManipulator */ - private $tableManipulator; + private TableManipulator $tableManipulator; /** * The toolbox for file. * - * @var ToolboxFile|null + * @var ToolboxFile */ - private $toolboxFile; + private ToolboxFile $toolboxFile; /** * The string util. * - * @var Adapter|StringUtil|null + * @var Adapter */ - private $stringUtil; + private Adapter $stringUtil; /** * The validator. * - * @var Adapter|Validator|null + * @var Adapter */ - private $validator; + private Adapter $validator; /** * The repository for files. * - * @var Adapter|FilesModel|null + * @var Adapter */ - private $fileRepository; + private Adapter $fileRepository; /** * The contao configurations. * - * @var Adapter|Config|null + * @var Adapter */ - private $config; + private Adapter $config; /** * Create a new instance. * - * @param IMetaModel $metaModel The MetaModel instance this attribute belongs to. - * @param array $information The attribute information. - * @param Connection|null $connection The database connection. - * @param TableManipulator|null $tableManipulator Table manipulator instance. - * @param ToolboxFile|null $toolboxFile The toolbox for file. - * @param Adapter|StringUtil|null $stringUtil The string util. - * @param Adapter|Validator|null $validator The validator. - * @param Adapter|FilesModel|null $fileRepository The repository for files. - * @param Adapter|Config|null $config The contao configurations. + * @param IMetaModel $metaModel The MetaModel instance this attribute belongs to. + * @param array $information The attribute information. + * @param Connection|null $connection The database connection. + * @param TableManipulator|null $tableManipulator Table manipulator instance. + * @param ToolboxFile|null $toolboxFile The toolbox for file. + * @param Adapter|null $stringUtil The string util. + * @param Adapter|null $validator The validator. + * @param Adapter|null $fileRepository The repository for files. + * @param Adapter|null $config The contao configurations. */ public function __construct( IMetaModel $metaModel, @@ -124,64 +141,71 @@ public function __construct( ) { parent::__construct($metaModel, $information); - if (null === $toolboxFile) { - // @codingStandardsIgnoreStart - @\trigger_error( - '"toolboxFile"" is missing. It has to be passed in the constructor.' . - 'Fallback will get removed in MetaModels 3.0', - E_USER_DEPRECATED - ); - // @codingStandardsIgnoreEnd + if (null === $connection) { + $connection = $this->fetchServiceForFallback('connection', 'database_connection'); + assert($connection instanceof Connection); + } - $toolboxFile = System::getContainer()->get('metamodels.attribute_file.toolbox.file'); + if (null === $tableManipulator) { + $tableManipulator = $this->fetchServiceForFallback('tableManipulator', 'metamodels.table_manipulator'); + assert($tableManipulator instanceof TableManipulator); + } + + if (null === $toolboxFile) { + $toolboxFile = $this->fetchServiceForFallback('toolboxFile', 'MetaModels\Helper\ToolboxFile'); + assert($toolboxFile instanceof ToolboxFile); } if (null === $stringUtil) { // @codingStandardsIgnoreStart - @\trigger_error( + @trigger_error( '"stringUtil"" is missing. It has to be passed in the constructor.' . 'Fallback will get removed in MetaModels 3.0', E_USER_DEPRECATED ); // @codingStandardsIgnoreEnd - $stringUtil = System::getContainer()->get('contao.framework')->getAdapter(StringUtil::class); + $stringUtil = System::getContainer()->get('contao.framework')?->getAdapter(StringUtil::class); + assert($stringUtil instanceof Adapter); } if (null === $validator) { // @codingStandardsIgnoreStart - @\trigger_error( + @trigger_error( '"validator"" is missing. It has to be passed in the constructor.' . 'Fallback will get removed in MetaModels 3.0', E_USER_DEPRECATED ); // @codingStandardsIgnoreEnd - $validator = System::getContainer()->get('contao.framework')->getAdapter(Validator::class); + $validator = System::getContainer()->get('contao.framework')?->getAdapter(Validator::class); + assert($validator instanceof Adapter); } if (null === $fileRepository) { // @codingStandardsIgnoreStart - @\trigger_error( + @trigger_error( '"fileRepository"" is missing. It has to be passed in the constructor.' . 'Fallback will get removed in MetaModels 3.0', E_USER_DEPRECATED ); // @codingStandardsIgnoreEnd - $fileRepository = System::getContainer()->get('contao.framework')->getAdapter(FilesModel::class); + $fileRepository = System::getContainer()->get('contao.framework')?->getAdapter(FilesModel::class); + assert($fileRepository instanceof Adapter); } if (null === $config) { // @codingStandardsIgnoreStart - @\trigger_error( + @trigger_error( '"config"" is missing. It has to be passed in the constructor.' . 'Fallback will get removed in MetaModels 3.0', E_USER_DEPRECATED ); // @codingStandardsIgnoreEnd - $config = System::getContainer()->get('contao.framework')->getAdapter(Config::class); + $config = System::getContainer()->get('contao.framework')?->getAdapter(Config::class); + assert($config instanceof Adapter); } $this->connection = $connection; @@ -198,16 +222,24 @@ public function __construct( */ public function destroyAUX() { + if ($this->isManagedAttribute($this->get('type'))) { + $this->triggerDeprecationShouldNotCallManaged(static::class, __METHOD__); + return; + } + + $this->triggerDeprecationIsUnmanagedAttribute(static::class, __METHOD__); + + /** @psalm-suppress DeprecatedMethod */ parent::destroyAUX(); $metaModel = $this->getMetaModel()->getTableName(); // Try to delete the column. If it does not exist as we can assume it has been deleted already then. - $tableColumns = $this->connection->getSchemaManager()->listTableColumns($metaModel); - if (($colName = $this->getColName()) && \array_key_exists($colName, $tableColumns)) { + $tableColumns = $this->connection->createSchemaManager()->listTableColumns($metaModel); + if (($colName = $this->getColName()) && array_key_exists($colName, $tableColumns)) { $this->tableManipulator->dropColumn($metaModel, $colName); } - if (\array_key_exists($colName . '__sort', $tableColumns)) { + if (array_key_exists($colName . '__sort', $tableColumns)) { $this->tableManipulator->dropColumn($metaModel, $colName . '__sort'); } } @@ -217,6 +249,14 @@ public function destroyAUX() */ public function initializeAUX() { + if ($this->isManagedAttribute($this->get('type'))) { + $this->triggerDeprecationShouldNotCallManaged(static::class, __METHOD__); + return; + } + + $this->triggerDeprecationIsUnmanagedAttribute(static::class, __METHOD__); + + /** @psalm-suppress DeprecatedMethod */ parent::initializeAUX(); if ($colName = $this->getColName()) { $tableName = $this->getMetaModel()->getTableName(); @@ -225,23 +265,53 @@ public function initializeAUX() } /** + * Search for file names or UUIDs. + * Find items if one or more files are stored (serialised array) or the parent folder has been selected. + * * {@inheritdoc} */ - public function searchFor($strPattern) + public function searchFor($strPattern): ?array { $subSelect = $this->connection->createQueryBuilder(); $subSelect - ->select('f.uuid') - ->from('tl_files', 'f') - ->where($subSelect->expr()->like('f.path', ':value')); + ->select('f.uuid', 'f.pid') + ->from('tl_files', 'f'); + + if (Validator::isUuid($uuid = trim($strPattern, '*'))) { + $subSelect + ->where(('f.uuid = :value')) + ->setParameter('value', StringUtil::uuidToBin($uuid)); + } else { + $subSelect + ->where($subSelect->expr()->like('f.name', ':value')) + ->setParameter('value', str_replace(['*', '?'], ['%', '_'], $strPattern)); + } + + if ([] === ($subResults = $subSelect->executeQuery()->fetchAllAssociative())) { + return []; + } + $builder = $this->connection->createQueryBuilder(); $builder ->select('t.id') - ->from($this->getMetaModel()->getTableName(), 't') - ->where($builder->expr()->in($this->getColName(), $subSelect->getSQL())) - ->setParameter('value', \str_replace(['*', '?'], ['%', '_'], $strPattern)); + ->from($this->getMetaModel()->getTableName(), 't'); + + $uuids = []; + foreach ($subResults as $subResult) { + $uuids[$subResult['pid']] = $subResult['pid']; + $uuids[$subResult['uuid']] = $subResult['uuid']; + } + $colName = $this->getColName(); + foreach (array_values($uuids) as $key => $uuid) { + $builder + ->orWhere(sprintf('t.%s LIKE :value_%s', $colName, $key)) + ->setParameter('value_' . $key, '%' . $uuid . '%'); + } + + $statement = $builder->executeQuery(); - return $builder->execute()->fetchAll(\PDO::FETCH_COLUMN); + // Return value list as list, parent function wants a list so we make a cast. + return array_map(static fn(mixed $value) => (string) $value, $statement->fetchFirstColumn()); } /** @@ -255,13 +325,13 @@ public function unsetDataFor($arrIds) ->set('t.' . $this->getColName(), ':null') ->where($builder->expr()->in('t.id', ':values')) ->setParameter('null', null) - ->setParameter('values', $arrIds, Connection::PARAM_STR_ARRAY); + ->setParameter('values', $arrIds, ArrayParameterType::STRING); if ($this->getMetaModel()->hasAttribute($this->getColName() . '__sort')) { $builder->set('t.' . $this->getColName() . '__sort', ':null'); } - $builder->execute(); + $builder->executeQuery(); } /** @@ -272,24 +342,25 @@ public function getDataFor($arrIds) $builder = $this->connection->createQueryBuilder(); $builder - ->select('t.id', 't.' . $this->getColName() . ' AS file') + ->select('t.id, t.' . $this->getColName() . ' AS file') ->from($this->getMetaModel()->getTableName(), 't') ->where($builder->expr()->in('t.id', ':values')) - ->setParameter('values', $arrIds, Connection::PARAM_STR_ARRAY); + ->setParameter('values', $arrIds, ArrayParameterType::STRING); if ($hasSort = $this->getMetaModel()->hasAttribute($this->getColName() . '__sort')) { $builder->addSelect($this->getColName() . '__sort AS file_sort'); } - $query = $builder->execute(); + $query = $builder->executeQuery(); $data = []; - while ($result = $query->fetch(\PDO::FETCH_OBJ)) { - $row = $this->toolboxFile->convertValuesToMetaModels($this->stringUtil->deserialize($result->file, true)); + while ($result = $query->fetchAssociative()) { + $row = + $this->toolboxFile->convertValuesToMetaModels($this->stringUtil->deserialize($result['file'], true)); if ($hasSort) { // The sort key be can remove in later version. The new sort key is bin_sorted. - $row['sort'] = $sorted = $this->stringUtil->deserialize($result->file_sort, true); + $row['sort'] = $sorted = $this->stringUtil->deserialize($result['file_sort'], true); foreach ($this->toolboxFile->convertValuesToMetaModels($sorted) as $sortedKey => $sortedValue) { $row[$sortedKey . '_sorted'] = $sortedValue; @@ -297,7 +368,7 @@ public function getDataFor($arrIds) if (isset($row['sort'])) { // @codingStandardsIgnoreStart - @\trigger_error( + @trigger_error( 'The sort key from the attribute file is deprecated since 2.1 and where removed in 3.0' . 'Use the key bin_sorted', E_USER_DEPRECATED @@ -306,7 +377,7 @@ public function getDataFor($arrIds) } } - $data[$result->id] = $row; + $data[$result['id']] = $row; } return $data; @@ -331,9 +402,9 @@ public function setDataFor($arrValues) // Check single file or multiple file. if ($this->get('file_multiple')) { - $files = \serialize($files); + $files = serialize($files); } else { - $files = $files[0]; + $files = $files[0] ?? null; } $this->connection @@ -343,7 +414,7 @@ public function setDataFor($arrValues) ->where('t.id=:id') ->setParameter($this->getColName(), $files) ->setParameter('id', $id) - ->execute(); + ->executeQuery(); } } @@ -360,7 +431,7 @@ public function getFilterOptions($idList, $usedOnly, &$arrCount = null) */ public function getAttributeSettingNames() { - return \array_merge( + return array_merge( parent::getAttributeSettingNames(), [ 'file_multiple', @@ -401,10 +472,10 @@ public function serializeData($mixValues) // Check single file or multiple file. if ($this->get('file_multiple')) { - return \serialize($data); + return serialize($data); } - return $data[0]; + return $data[0] ?? ''; } /** @@ -420,8 +491,8 @@ private function handleCustomFileTree(&$arrFieldDef) // Set root path of file chooser depending on contao version. $file = null; - if ($this->validator->isUuid($this->get('file_uploadFolder'))) { - $file = $this->fileRepository->findByUuid($this->get('file_uploadFolder')); + if ($this->validator->isUuid($this->get('file_uploadFolder') ?? '')) { + $file = $this->fileRepository->findByUuid($this->get('file_uploadFolder') ?? ''); } // Check if we have a file. @@ -440,11 +511,11 @@ private function handleCustomFileTree(&$arrFieldDef) switch ($this->get('file_filesOnly')) { case '1': // Files only. - $fieldDefinition['eval']['filesOnly'] = true; + $arrFieldDef['eval']['filesOnly'] = true; break; case '2': // Folders only. - $fieldDefinition['eval']['files'] = false; + $arrFieldDef['eval']['files'] = false; break; default: // Files and files possible. @@ -465,9 +536,7 @@ public function getFieldDefinition($arrOverrides = []) $widgetMode = $this->getOverrideValue('file_widgetMode', $arrOverrides); - if (('normal' !== $widgetMode) - && ((bool) $this->get('file_multiple')) - ) { + if (('normal' !== $widgetMode) && ((bool) $this->get('file_multiple'))) { $fieldDefinition['eval']['orderField'] = $this->getColName() . '__sort'; } @@ -508,18 +577,32 @@ public function widgetToValue($varValue, $itemId) * * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - protected function prepareTemplate(Template $template, $rowData, $settings) + protected function prepareTemplate(Template $objTemplate, $arrRowData, $objSettings) { - parent::prepareTemplate($template, $rowData, $settings); + parent::prepareTemplate($objTemplate, $arrRowData, $objSettings); + + /** @var array{ + * bin: list, + * value: list, + * path: list, + * meta: list, + * bin_sorted?: list, + * value_sorted?: list, + * path_sorted?: list, + * meta_sorted?: list + * }|null $value */ + $value = $arrRowData[$this->getColName()] ?? null; + if (null === $value) { + $value = ['bin' => [], 'value' => [], 'path' => [], 'meta' => []]; + } - $value = $rowData[$this->getColName()]; + $showImage = (bool) $objSettings->get('file_showImage'); // No data and show image, check placeholder. - if (!($value['bin'] ?? null)) { - if (null === $settings->get('file_showImage') - || null === ($placeholder = $settings->get('file_placeholder'))) { - $template->files = []; - $template->src = []; + if ([] === $value['bin']) { + if (null === ($placeholder = $objSettings->get('file_placeholder'))) { + $objTemplate->files = []; + $objTemplate->src = []; return; } @@ -530,45 +613,53 @@ protected function prepareTemplate(Template $template, $rowData, $settings) $toolbox = clone $this->toolboxFile; + /** @psalm-suppress DeprecatedMethod */ $toolbox ->setBaseLanguage($this->getMetaModel()->getActiveLanguage()) ->setFallbackLanguage($this->getMetaModel()->getFallbackLanguage()) ->setLightboxId( - \sprintf( + sprintf( '%s.%s.%s', $this->getMetaModel()->getTableName(), - $settings->get('id'), - $rowData['id'] + (string) ($objSettings->get('id') ?? ''), + (string) ($arrRowData['id'] ?? '0') ) ) - ->setShowImages($settings->get('file_showImage')); + ->setShowImages($showImage); if ($this->get('file_validFileTypes')) { $toolbox->setAcceptedExtensions($this->get('file_validFileTypes')); } - if ($settings->get('file_imageSize')) { - $toolbox->setResizeImages($settings->get('file_imageSize')); + if (is_array($imageSize = $objSettings->get('file_imageSize'))) { + $toolbox->setResizeImages($imageSize); } - if (isset($value['value'])) { - foreach ($value['value'] as $strFile) { - $toolbox->addPathById($strFile); - } - } elseif (\is_array($value)) { - foreach ($value as $strFile) { - $toolbox->addPathById($strFile); - } - } else { - $toolbox->addPathById($value); + foreach ($value['value'] ?? [] as $strFile) { + $toolbox->addPathById($strFile); } - $toolbox->withDownloadKeys($settings->get('file_showLink') && $settings->get('file_protectedDownload')); + $toolbox->withDownloadKeys( + ((bool) $objSettings->get('file_showLink')) && ((bool) $objSettings->get('file_protectedDownload')) + ); $toolbox->resolveFiles(); - $data = $toolbox->sortFiles($settings->get('file_sortBy'), ($value['bin_sorted'] ?? [])); + $data = $toolbox->sortFiles($objSettings->get('file_sortBy') ?? 'name_asc', ($value['bin_sorted'] ?? [])); + + $objTemplate->files = $data['files']; + $objTemplate->src = $data['source']; + } + + private function fetchServiceForFallback(string $parameter, string $serviceName): null|object + { + // @codingStandardsIgnoreStart + @trigger_error( + '"'. $parameter . '" is missing. It has to be passed in the constructor.' . + 'Fallback will get removed in MetaModels 3.0', + E_USER_DEPRECATED + ); + // @codingStandardsIgnoreEnd - $template->files = $data['files']; - $template->src = $data['source']; + return System::getContainer()->get($serviceName); } } diff --git a/src/Attribute/FileOrder.php b/src/Attribute/FileOrder.php index 86c6ad6..9f0faf7 100644 --- a/src/Attribute/FileOrder.php +++ b/src/Attribute/FileOrder.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2022 The MetaModels team. + * (c) 2012-2023 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,7 +15,7 @@ * @author Sven Baumann * @author Stefan Heimes * @author Ingolf Steinhardt - * @copyright 2012-2022 The MetaModels team. + * @copyright 2012-2023 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -24,7 +24,6 @@ use Contao\StringUtil; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Platforms\Keywords\KeywordList; use MetaModels\Attribute\ISimple; use MetaModels\Attribute\IInternal; use MetaModels\IMetaModel; @@ -41,30 +40,30 @@ class FileOrder implements ISimple, IInternal * * @var IMetaModel */ - private $metaModel; + private IMetaModel $metaModel; /** * The column name. * * @var string */ - private $colName; + private string $colName; /** * The connection. * * @var Connection */ - private $connection; + private Connection $connection; /** * Create a new instance. * - * @param null $metaModel The MetaModel. + * @param IMetaModel $metaModel The MetaModel. * @param array $information The attribute information. * @param Connection $connection The connection. */ - public function __construct($metaModel, array $information, Connection $connection) + public function __construct(IMetaModel $metaModel, array $information, Connection $connection) { $this->metaModel = $metaModel; $this->colName = $information['colname']; @@ -76,7 +75,7 @@ public function __construct($metaModel, array $information, Connection $connecti */ public function getName() { - return null; + return ''; } /** @@ -202,7 +201,7 @@ public function setDataFor($arrValues) ->where('t.id=:id') ->setParameter($this->getColName(), $value ?: $this->serializeData([])) ->setParameter('id', $id) - ->execute(); + ->executeQuery(); } } diff --git a/src/ContaoManager/Plugin.php b/src/ContaoManager/Plugin.php index 573be26..c5f9410 100644 --- a/src/ContaoManager/Plugin.php +++ b/src/ContaoManager/Plugin.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2019 The MetaModels team. + * (c) 2012-2024 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,7 +13,8 @@ * @package MetaModels/attribute_file * @author Christian Schiffler * @author Sven Baumann - * @copyright 2012-2019 The MetaModels team. + * @author Ingolf Steinhardt + * @copyright 2012-2024 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -35,7 +36,7 @@ class Plugin implements BundlePluginInterface /** * {@inheritdoc} */ - public function getBundles(ParserInterface $parser) + public function getBundles(ParserInterface $parser): array { return [ BundleConfig::create(MetaModelsAttributeFileBundle::class) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 8c51c0e..d945b14 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2019 The MetaModels team. + * (c) 2012-2025 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,7 +12,8 @@ * * @package MetaModels/attribute_file * @author Sven Baumann - * @copyright 2012-2019 The MetaModels team. + * @author Ingolf Steinhardt + * @copyright 2012-2025 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -21,6 +22,7 @@ namespace MetaModels\AttributeFileBundle\DependencyInjection; +use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -34,25 +36,16 @@ final class Configuration implements ConfigurationInterface * * @var bool */ - private $debug; - - /** - * The root directory. - * - * @var string - */ - private $rootDir; + private bool $debug; /** * Constructor. * - * @param bool $debug The debug flag. - * @param string|null $rootDir The root directory. + * @param bool $debug The debug flag. */ - public function __construct(bool $debug, ?string $rootDir) + public function __construct(bool $debug) { - $this->debug = $debug; - $this->rootDir = $rootDir; + $this->debug = $debug; } /** @@ -60,18 +53,17 @@ public function __construct(bool $debug, ?string $rootDir) */ public function getConfigTreeBuilder(): TreeBuilder { - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root('metamodels_attribute_file'); + $treeBuilder = new TreeBuilder('metamodels_attribute_file'); - $rootNode - ->children() - ->booleanNode('enable_cache') - ->defaultValue(!$this->debug) - ->end() - ->scalarNode('cache_dir') - ->defaultValue('%metamodels.cache_dir%' . DIRECTORY_SEPARATOR . 'attribute_file') - ->end() + $rootNode = $treeBuilder->getRootNode(); + assert($rootNode instanceof ArrayNodeDefinition); + $children = $rootNode->children(); + $children->booleanNode('enable_cache')->defaultValue(!$this->debug)->end(); + $children + ->scalarNode('cache_dir') + ->defaultValue('%metamodels.cache_dir%' . DIRECTORY_SEPARATOR . 'attribute_file') ->end(); + $children->booleanNode('file_usage')->defaultValue(false)->end(); return $treeBuilder; } diff --git a/src/DependencyInjection/MetaModelsAttributeFileExtension.php b/src/DependencyInjection/MetaModelsAttributeFileExtension.php index c57eeeb..38d6790 100644 --- a/src/DependencyInjection/MetaModelsAttributeFileExtension.php +++ b/src/DependencyInjection/MetaModelsAttributeFileExtension.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2020 The MetaModels team. + * (c) 2012-2025 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,21 +13,29 @@ * @package MetaModels/attribute_file * @author Christian Schiffler * @author Sven Baumann - * @copyright 2012-2020 The MetaModels team. + * @author Ingolf Steinhardt + * @copyright 2012-2025 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ namespace MetaModels\AttributeFileBundle\DependencyInjection; -use Doctrine\Common\Cache\ArrayCache; +use InspiredMinds\ContaoFileUsage\ContaoFileUsageBundle; use MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\DcaSetting\FileWidgetModeOptions; use MetaModels\ContaoFrontendEditingBundle\MetaModelsContaoFrontendEditingBundle; +use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader; +use function assert; +use function in_array; +use function is_array; +use function is_bool; + /** * This is the class that loads and manages the bundle configuration */ @@ -35,36 +43,55 @@ class MetaModelsAttributeFileExtension extends Extension { /** * {@inheritDoc} + * + * @SuppressWarnings(PHPMD.LongVariable) */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('factory.yml'); $loader->load('event_listener.yml'); $loader->load('services.yml'); - $config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs); + $configuration = $this->getConfiguration($configs, $container); + assert($configuration instanceof Configuration); + $config = $this->processConfiguration($configuration, $configs); $this->buildCacheService($container, $config); + $bundles = $container->getParameter('kernel.bundles'); + assert(is_array($bundles)); + + // Load configuration for the frontend editing extension. $frontendEditing = false; - // Load configuration for the frontend editing. - if (\in_array(MetaModelsContaoFrontendEditingBundle::class, $container->getParameter('kernel.bundles'), true)) { + if (in_array(MetaModelsContaoFrontendEditingBundle::class, $bundles, true)) { $frontendEditing = true; $loader->load('frontend_editing/event_listener.yml'); } - $this->addFrontendEditingArgument($container, $frontendEditing); + + // Load configuration for the file usage extension. + if (in_array(ContaoFileUsageBundle::class, $bundles, true) && (bool) ($config['file_usage'] ?? false)) { + $loader->load('file_usage/services.yml'); + } + + // Schema manager + $typeNames = $container->hasParameter('metamodels.managed-schema-type-names') + ? $container->getParameter('metamodels.managed-schema-type-names') + : null; + $managedSchemaTypeNames = is_array($typeNames) ? $typeNames : []; + $managedSchemaTypeNames[] = 'file'; + $container->setParameter('metamodels.managed-schema-type-names', $managedSchemaTypeNames); } /** * {@inheritDoc} */ - public function getConfiguration(array $config, ContainerBuilder $container) + public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface { - return new Configuration( - $container->getParameter('kernel.debug'), - $container->getParameter('metamodels.cache_dir') - ); + $debug = $container->getParameter('kernel.debug'); + assert(is_bool($debug)); + + return new Configuration($debug); } /** @@ -75,12 +102,12 @@ public function getConfiguration(array $config, ContainerBuilder $container) * * @return void */ - private function buildCacheService(ContainerBuilder $container, array $config) + private function buildCacheService(ContainerBuilder $container, array $config): void { - // if cache disabled, swap it out with the dummy cache. + // If cache disabled, swap it out with the dummy cache. if (!$config['enable_cache']) { $cache = $container->getDefinition('metamodels.attribute_file.cache_system'); - $cache->setClass(ArrayCache::class); + $cache->setClass(ArrayAdapter::class); $cache->setArguments([]); $container->setParameter('metamodels.attribute_file.cache_dir', null); return; diff --git a/src/EventListener/BuildAttributeListener.php b/src/EventListener/BuildAttributeListener.php index 9a23fab..979c121 100644 --- a/src/EventListener/BuildAttributeListener.php +++ b/src/EventListener/BuildAttributeListener.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2019 The MetaModels team. + * (c) 2012-2024 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,7 +13,8 @@ * @package MetaModels/attribute_file * @author Stefan Heimes * @author Sven Baumann - * @copyright 2012-2019 The MetaModels team. + * @author Ingolf Steinhardt + * @copyright 2012-2024 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -24,11 +25,8 @@ use MetaModels\AttributeFileBundle\Attribute\File; use MetaModels\AttributeFileBundle\DcGeneral\AttributeFileDefinition; use MetaModels\DcGeneral\Events\MetaModel\BuildAttributeEvent; -use \ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface; +use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface; -/** - * Class Attribute - */ class BuildAttributeListener { /** @@ -41,7 +39,10 @@ class BuildAttributeListener public function buildAttribute(BuildAttributeEvent $event) { $attribute = $event->getAttribute(); - if (!($attribute instanceof File) || !$attribute->get('file_multiple')) { + if ( + !($attribute instanceof File) + || !$attribute->get('file_multiple') + ) { return; } @@ -50,15 +51,14 @@ public function buildAttribute(BuildAttributeEvent $event) $name = $attribute->getColName(); $nameSort = \sprintf('%s__sort', $name); - if ($properties->hasProperty($nameSort)) { - $this->addAttributeToDefinition($container, $name); - $properties->getProperty($name . '__sort')->setWidgetType('fileTreeOrder'); - - return; + if (!$properties->hasProperty($nameSort)) { + $properties->addProperty(new DefaultProperty($nameSort)); } - $properties->addProperty($property = new DefaultProperty($name . '__sort')); - $property->setWidgetType('fileTreeOrder'); + $properties->getProperty($nameSort) + ->setWidgetType('fileTreeOrder') + ->setLabel($nameSort) + ->setExtra(['tl_class' => 'hidden']); $this->addAttributeToDefinition($container, $name); } @@ -67,17 +67,19 @@ public function buildAttribute(BuildAttributeEvent $event) * Add attribute to MetaModels file attributes definition. * * @param ContainerInterface $container The metamodel data definition. - * * @param string $name The attribute name. * * @return void */ - private function addAttributeToDefinition(ContainerInterface $container, $name) + private function addAttributeToDefinition(ContainerInterface $container, string $name): void { if (!$container->hasDefinition('metamodels.file-attributes')) { $container->setDefinition('metamodels.file-attributes', new AttributeFileDefinition()); } - $container->getDefinition('metamodels.file-attributes')->add($name); + $definition = $container->getDefinition('metamodels.file-attributes'); + assert($definition instanceof AttributeFileDefinition); + + $definition->add($name); } } diff --git a/src/EventListener/BuildDataDefinitionListener.php b/src/EventListener/BuildDataDefinitionListener.php index 77b438e..b828905 100644 --- a/src/EventListener/BuildDataDefinitionListener.php +++ b/src/EventListener/BuildDataDefinitionListener.php @@ -21,6 +21,7 @@ use ContaoCommunityAlliance\DcGeneral\Factory\Event\BuildDataDefinitionEvent; use ContaoCommunityAlliance\DcGeneral\DataDefinition\Palette\Property; +use MetaModels\AttributeFileBundle\DcGeneral\AttributeFileDefinition; /** * Class BuildDataDefinitionListener @@ -41,13 +42,16 @@ public function buildDataDefinition(BuildDataDefinitionEvent $event) return; } // All properties... - foreach ($container->getDefinition('metamodels.file-attributes')->get() as $propertyName) { + $definition = $container->getDefinition('metamodels.file-attributes'); + assert($definition instanceof AttributeFileDefinition); + foreach ($definition->get() as $propertyName) { // ... in all palettes ... foreach ($container->getPalettesDefinition()->getPalettes() as $palette) { // ... in any legend ... foreach ($palette->getLegends() as $legend) { // ... of the searched name ... - if (($legend->hasProperty($propertyName)) + if ( + ($legend->hasProperty($propertyName)) && ($container->getPropertiesDefinition()->hasProperty($propertyName . '__sort')) ) { // ... must have the order field as companion, visible only when the real property is. diff --git a/src/EventListener/BuildFrontendUploadListener.php b/src/EventListener/BuildFrontendUploadListener.php index b6842e5..f616d08 100644 --- a/src/EventListener/BuildFrontendUploadListener.php +++ b/src/EventListener/BuildFrontendUploadListener.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2022 The MetaModels team. + * (c) 2012-2023 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,7 +13,7 @@ * @package MetaModels/attribute_file * @author Sven Baumann * @author Ingolf Steinhardt - * @copyright 2012-2022 The MetaModels team. + * @copyright 2012-2023 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -22,23 +22,19 @@ namespace MetaModels\AttributeFileBundle\EventListener; -use Contao\FrontendUser; -use Contao\InsertTags; -use Contao\StringUtil; -use ContaoCommunityAlliance\DcGeneral\Contao\InputProvider; +use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator; use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminatorAwareTrait; -use ContaoCommunityAlliance\DcGeneral\InputProviderInterface; -use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Schema\Column; +use Contao\CoreBundle\InsertTag\InsertTagParser; +use Contao\FrontendUser; use MetaModels\AttributeFileBundle\Attribute\File; -use MetaModels\CoreBundle\Contao\InsertTag\ReplaceParam; -use MetaModels\CoreBundle\Contao\InsertTag\ReplaceTableName; use MetaModels\DcGeneral\Events\MetaModel\BuildAttributeEvent; use MetaModels\ViewCombination\ViewCombination; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; /** * This event build the attribute for upload field, in the frontend editing scope. + * + * @SuppressWarnings(PHPMD.UnusedPrivateField) */ final class BuildFrontendUploadListener { @@ -49,85 +45,44 @@ final class BuildFrontendUploadListener * * @var ViewCombination */ - private $viewCombination; + private ViewCombination $viewCombination; /** * The token storage. * * @var TokenStorageInterface */ - private $tokenStorage; + private TokenStorageInterface $tokenStorage; /** * The property information from the input screen. * * @var array */ - private $information; + private array $information = []; /** - * The insert tag replacer, for replace the table name. + * The insert tag parser. * - * @var ReplaceTableName + * @var InsertTagParser */ - private $replaceTableName; - - /** - * The insert tag replacer, for replace parameters. - * - * @var ReplaceParam - */ - private $replaceParam; - - /** - * The database connection. - * - * @var Connection - */ - private $connection; - - /** - * The input provider. - * - * @var InputProviderInterface - */ - private $inputProvider; - - /** - * The autoincrement. - * - * @var int - */ - private $autoincrement; - - /** - * The id column. - * - * @var Column - */ - private $columnId; + private InsertTagParser $insertTagParser; /** * The constructor. * * @param ViewCombination $viewCombination The view combination. * @param TokenStorageInterface $tokenStorage The token storage. - * @param ReplaceTableName $replaceTableName The insert tag replacer, for replace the table name. - * @param ReplaceParam $replaceParam The insert tag replacer, for replace parameters. - * @param Connection $connection The database connection. + * @param InsertTagParser $insertTagParser The insert tag parser. */ public function __construct( ViewCombination $viewCombination, TokenStorageInterface $tokenStorage, - ReplaceTableName $replaceTableName, - ReplaceParam $replaceParam, - Connection $connection + InsertTagParser $insertTagParser ) { $this->viewCombination = $viewCombination; $this->tokenStorage = $tokenStorage; - $this->replaceTableName = $replaceTableName; - $this->replaceParam = $replaceParam; - $this->connection = $connection; + $this->insertTagParser = $insertTagParser; } /** @@ -164,12 +119,12 @@ private function addWidgetModeInformationToProperty(BuildAttributeEvent $event): 'doNotOverwrite' => $this->information['fe_widget_file_doNotOverwrite'], 'deselect' => (bool) $this->information['fe_widget_file_deselect'], 'delete' => (bool) $this->information['fe_widget_file_delete'], - 'uploadFolder' => $this->getUserHomeDir() ?: $this->getTargetFolder(), - 'extendFolder' => $this->getExtendFolder($event), + 'uploadFolder' => $this->getUserHomeDir() ?? $this->getTargetFolder() ?? '', + 'extendFolder' => $this->getExtendFolder(), 'normalizeExtendFolder' => (bool) $this->information['fe_widget_file_normalize_extend_folder'], 'normalizeFilename' => (bool) $this->information['fe_widget_file_normalize_filename'], - 'prefixFilename' => $this->getPrefixFilename($event), - 'postfixFilename' => $this->getPostfixFilename($event), + 'prefixFilename' => $this->getPrefixFilename(), + 'postfixFilename' => $this->getPostfixFilename(), 'storeFile' => true, 'imageSize' => $this->information['fe_widget_file_imageSize'], 'sortBy' => $this->information['fe_widget_file_sortBy'], @@ -212,13 +167,13 @@ private function addWidgetModeInformationToProperty(BuildAttributeEvent $event): */ private function getUserHomeDir(): ?string { - /** @var FrontendUser $feUser */ - if ($this->information['fe_widget_file_useHomeDir'] - && ($user = $this->tokenStorage->getToken()) - && ($feUser = $user->getUser()) - && $feUser->assignDir - && $feUser->homeDir - ) { + if (!$this->information['fe_widget_file_useHomeDir'] || (null === ($user = $this->tokenStorage->getToken()))) { + return null; + } + $feUser = $user->getUser(); + assert($feUser instanceof FrontendUser); + + if (((bool) $feUser->assignDir) && $feUser->homeDir) { return $feUser->homeDir; } @@ -238,109 +193,53 @@ private function getTargetFolder(): ?string /** * Get the extend folder. * - * @param BuildAttributeEvent $event The event. - * * @return string|null */ - private function getExtendFolder(BuildAttributeEvent $event): ?string + private function getExtendFolder(): ?string { - if (!($extendFolder = $this->information['fe_widget_file_extend_folder']) - || (false === \strpos($extendFolder, '{{')) - ) { - return $extendFolder ?: null; - } - - return $this->replaceInsertTag($event, $extendFolder); + return $this->replaceInsertTagIfNeeded($this->information['fe_widget_file_extend_folder'] ?? null); } /** * Get the prefix for the filename. * - * @param BuildAttributeEvent $event The event. - * * @return string|null */ - private function getPrefixFilename(BuildAttributeEvent $event): ?string + private function getPrefixFilename(): ?string { - if (!($extendFolder = $this->information['fe_widget_file_prefix_filename']) - || (false === \strpos($extendFolder, '{{')) - ) { - return $extendFolder ?: null; - } - - return $this->replaceInsertTag($event, $extendFolder); + return $this->replaceInsertTagIfNeeded($this->information['fe_widget_file_prefix_filename'] ?? null); } /** * Get the postfix for the filename. * - * @param BuildAttributeEvent $event The event. - * * @return string|null */ - private function getPostfixFilename(BuildAttributeEvent $event): ?string + private function getPostfixFilename(): ?string { - if (!($extendFolder = $this->information['fe_widget_file_postfix_filename']) - || (false === \strpos($extendFolder, '{{')) - ) { - return $extendFolder ?: null; + return $this->replaceInsertTagIfNeeded($this->information['fe_widget_file_postfix_filename'] ?? null); + } + + private function replaceInsertTagIfNeeded(mixed $value): ?string + { + if (null === $value) { + return null; } + assert(\is_string($value)); - return $this->replaceInsertTag($event, $extendFolder); + return \str_contains($value, '{{') ? $this->replaceInsertTag($value) : $value; } /** - * Replace the insert tag. + * Replace the insert tag - without converting to esi tags. * - * @param BuildAttributeEvent $event The event. - * @param string $replace The replacement. + * @param string $replace The replacement. * * @return string - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - private function replaceInsertTag(BuildAttributeEvent $event, string $replace): string + private function replaceInsertTag(string $replace): string { - if ((!$this->autoincrement || !$this->columnId) - || !$this->getInputProvider()->hasParameter('act') - || ('create' === $this->getInputProvider()->getParameter('act')) - ) { - $tableDetails = $this->connection->getSchemaManager()->listTableDetails($event->getContainer()->getName()); - foreach ($tableDetails->getColumns() as $column) { - if (!$column->getAutoincrement()) { - continue; - } - - $this->columnId = $column; - break; - } - - if ($this->columnId) { - $this->autoincrement = (int) $tableDetails->getOption('autoincrement'); - } - } - - if ($this->autoincrement && $this->columnId) { - $this->getInputProvider()->setValue($this->columnId->getName(), $this->autoincrement); - } - - $replaced = $this->replaceParam->replace( - $this->replaceTableName->replace( - $event->getContainer()->getName(), - StringUtil::decodeEntities($replace) - ) - ); - - if ($this->autoincrement && $this->columnId) { - $this->getInputProvider()->unsetValue($this->columnId->getName()); - } - - if ((false === \strpos($replaced, '{{'))) { - return $replaced; - } - - $replacer = new InsertTags(); - return $replacer->replace($replaced); + return $this->insertTagParser->replaceInline($replace); } /** @@ -353,22 +252,8 @@ private function replaceInsertTag(BuildAttributeEvent $event, string $replace): private function storeFileToTempFolder(array $extra): bool { return (isset($extra['extendFolder']) && $extra['extendFolder']) - // Test if in the extend folder path find insert tag. - && (false !== \strpos($extra['extendFolder'], '{{')); - } - - /** - * Get the input provider. - * - * @return InputProviderInterface - */ - private function getInputProvider(): InputProviderInterface - { - if (null === $this->inputProvider) { - $this->inputProvider = new InputProvider(); - } - - return $this->inputProvider; + // Test if in the extent folder path find insert tag. + && (\str_contains($extra['extendFolder'], '{{')); } /** @@ -380,8 +265,11 @@ private function getInputProvider(): InputProviderInterface */ private function wantToHandle(BuildAttributeEvent $event): bool { - return $this->scopeDeterminator->currentScopeIsFrontend() - && !$this->scopeDeterminator->currentScopeIsUnknown() + $scopeDeterminator = $this->scopeDeterminator; + assert($scopeDeterminator instanceof RequestScopeDeterminator); + + return $scopeDeterminator->currentScopeIsFrontend() + && !$scopeDeterminator->currentScopeIsUnknown() && $this->isSingleUploadField($event); } @@ -394,11 +282,12 @@ private function wantToHandle(BuildAttributeEvent $event): bool */ private function isSingleUploadField(BuildAttributeEvent $event): bool { - $properties = []; - if (!(($attribute = $event->getAttribute()) instanceof File) - || !($inputScreen = $this->viewCombination->getScreen($event->getContainer()->getName())) - || !(isset($inputScreen['properties']) && ($properties = $inputScreen['properties'])) - ) { + if (!(($attribute = $event->getAttribute()) instanceof File)) { + return false; + } + $inputScreen = $this->viewCombination->getScreen($event->getContainer()->getName()); + + if ((null === $inputScreen) || (!\is_array($properties = $inputScreen['properties'] ?? null))) { return false; } @@ -409,7 +298,8 @@ private function isSingleUploadField(BuildAttributeEvent $event): bool 'fe_multiple_upload_preview' ]; $information = $properties[\array_flip(\array_column($properties, 'attr_id'))[$attribute->get('id')]]; - if (!isset($information['file_widgetMode']) + if ( + !isset($information['file_widgetMode']) || !\in_array($information['file_widgetMode'], $supportedModes, true) ) { return false; diff --git a/src/EventListener/DcGeneral/Table/Attribute/RemoveTypeOptions.php b/src/EventListener/DcGeneral/Table/Attribute/RemoveTypeOptions.php index b791c00..1cfa8e2 100644 --- a/src/EventListener/DcGeneral/Table/Attribute/RemoveTypeOptions.php +++ b/src/EventListener/DcGeneral/Table/Attribute/RemoveTypeOptions.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2019 The MetaModels team. + * (c) 2012-2023 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,7 +12,8 @@ * * @package MetaModels/attribute_file * @author Sven Baumann - * @copyright 2012-2019 The MetaModels team. + * @author Ingolf Steinhardt + * @copyright 2012-2023 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -20,6 +21,7 @@ namespace MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\Attribute; use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetPropertyOptionsEvent; +use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface; /** * This class provide functions for remove type options, from the attribute table. @@ -35,15 +37,17 @@ class RemoveTypeOptions */ public function removeOption(GetPropertyOptionsEvent $event) { - $environment = $event->getEnvironment(); - if (('type' !== $event->getPropertyName()) - || ('tl_metamodel_attribute' !== $environment->getDataDefinition()->getName()) + $dataDefinition = $event->getEnvironment()->getDataDefinition(); + assert($dataDefinition instanceof ContainerInterface); + if ( + ('type' !== $event->getPropertyName()) + || ('tl_metamodel_attribute' !== $dataDefinition->getName()) ) { return; } $options = $event->getOptions(); - if (!\array_key_exists('filesort', $options)) { + if ((null === $options) || !\array_key_exists('filesort', $options)) { return; } diff --git a/src/EventListener/DcGeneral/Table/DcaSetting/FeeFileImageSizeOptions.php b/src/EventListener/DcGeneral/Table/DcaSetting/FeeFileImageSizeOptions.php new file mode 100644 index 0000000..e63bba8 --- /dev/null +++ b/src/EventListener/DcGeneral/Table/DcaSetting/FeeFileImageSizeOptions.php @@ -0,0 +1,90 @@ + + * @copyright 2012-2024 The MetaModels team. + * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later + * @filesource + */ + +declare(strict_types=1); + +namespace MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\DcaSetting; + +use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator; +use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetPropertyOptionsEvent; +use Doctrine\DBAL\Connection; +use MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsProvider; +use MetaModels\CoreBundle\EventListener\DcGeneral\Table\DcaSetting\AbstractListener; +use MetaModels\IFactory; + +/** + * Add the options for the FEE file image size. + */ +final class FeeFileImageSizeOptions extends AbstractListener +{ + public function __construct( + RequestScopeDeterminator $scopeDeterminator, + IFactory $factory, + Connection $connection, + private readonly ImageSizeOptionsProvider $optionsProvider, + ) { + parent::__construct($scopeDeterminator, $factory, $connection); + } + + /** + * Invoke the event. + * + * @param GetPropertyOptionsEvent $event The event. + * + * @return void + */ + public function __invoke(GetPropertyOptionsEvent $event): void + { + if ( + ('fe_widget_file_imageSize' !== $event->getPropertyName()) + || (false === $this->wantToHandle($event)) + || (false === $this->isAttributeFile($event)) + ) { + return; + } + + $this->optionsProvider->addOptions($event); + } + + /** + * If used attribute type of file. + * + * @param GetPropertyOptionsEvent $event The event. + * + * @return bool + */ + private function isAttributeFile(GetPropertyOptionsEvent $event): bool + { + $builder = $this->connection->createQueryBuilder(); + $builder + ->select('t.type') + ->from('tl_metamodel_attribute', 't') + ->where($builder->expr()->eq('t.id', ':id')) + ->setParameter('id', $event->getModel()->getProperty('attr_id')); + + $statement = $builder->executeQuery(); + if (0 === $statement->columnCount()) { + return false; + } + + $result = $statement->fetchAssociative(); + + return 'file' === ($result['type'] ?? null); + } +} diff --git a/src/EventListener/DcGeneral/Table/DcaSetting/FileWidgetModeOptions.php b/src/EventListener/DcGeneral/Table/DcaSetting/FileWidgetModeOptions.php index b0d7595..37af20f 100644 --- a/src/EventListener/DcGeneral/Table/DcaSetting/FileWidgetModeOptions.php +++ b/src/EventListener/DcGeneral/Table/DcaSetting/FileWidgetModeOptions.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2022 The MetaModels team. + * (c) 2012-2023 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,7 +13,7 @@ * @package MetaModels/attribute_file * @author Sven Baumann * @author Ingolf Steinhardt - * @copyright 2012-2022 The MetaModels team. + * @copyright 2012-2023 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -38,7 +38,7 @@ class FileWidgetModeOptions extends AbstractListener * * @var bool */ - private $frontendEditing; + private bool $frontendEditing; /** * {@inheritDoc} @@ -62,7 +62,8 @@ public function __construct( */ public function __invoke(GetPropertyOptionsEvent $event): void { - if (('file_widgetMode' !== $event->getPropertyName()) + if ( + ('file_widgetMode' !== $event->getPropertyName()) || (false === $this->wantToHandle($event)) || (false === $this->isAttributeFile($event)) ) { @@ -94,7 +95,7 @@ private function addOptions(GetPropertyOptionsEvent $event): void ); } - $event->setOptions(\array_values(\array_unique(\array_merge($event->getOptions(), $addOptions)))); + $event->setOptions(\array_values(\array_unique(\array_merge($event->getOptions() ?? [], $addOptions)))); } /** @@ -113,13 +114,14 @@ private function isAttributeFile(GetPropertyOptionsEvent $event): bool ->where($builder->expr()->eq('t.id', ':id')) ->setParameter('id', $event->getModel()->getProperty('attr_id')); - $statement = $builder->execute(); + $statement = $builder->executeQuery(); if (0 === $statement->columnCount()) { return false; } - $result = $statement->fetch(\PDO::FETCH_OBJ); - return 'file' === $result->type; + $result = $statement->fetchAssociative(); + + return 'file' === ($result['type'] ?? null); } /** diff --git a/src/EventListener/DcGeneral/Table/FilterSetting/RemoveAttIdOptions.php b/src/EventListener/DcGeneral/Table/FilterSetting/RemoveAttIdOptions.php index e027b89..c4da897 100644 --- a/src/EventListener/DcGeneral/Table/FilterSetting/RemoveAttIdOptions.php +++ b/src/EventListener/DcGeneral/Table/FilterSetting/RemoveAttIdOptions.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2019 The MetaModels team. + * (c) 2012-2023 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,7 +12,7 @@ * * @package MetaModels/attribute_file * @author Sven Baumann - * @copyright 2012-2019 The MetaModels team. + * @copyright 2012-2023 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -20,6 +20,7 @@ namespace MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\FilterSetting; use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetPropertyOptionsEvent; +use ContaoCommunityAlliance\DcGeneral\DataDefinition\ContainerInterface; /** * This class provide functions for remove type options, from the filter setting table. @@ -35,17 +36,19 @@ class RemoveAttIdOptions */ public function removeOption(GetPropertyOptionsEvent $event) { - $environment = $event->getEnvironment(); - if (('attr_id' !== $event->getPropertyName()) - || ('tl_metamodel_filtersetting' !== $environment->getDataDefinition()->getName()) + $dataDefinition = $event->getEnvironment()->getDataDefinition(); + assert($dataDefinition instanceof ContainerInterface); + if ( + ('attr_id' !== $event->getPropertyName()) + || ('tl_metamodel_filtersetting' !== $dataDefinition->getName()) ) { return; } - $options = $event->getOptions(); + $options = $event->getOptions() ?? []; foreach ($options as $key => $name) { $sortKey = $key . '__sort'; - if (\array_key_exists($sortKey, $options) && ('[file]' === \substr($name, -\strlen('[file]')))) { + if (\array_key_exists($sortKey, $options) && (\str_ends_with($name, '[file]'))) { unset($options[$sortKey]); } } diff --git a/src/EventListener/DcGeneral/Table/RenderSetting/FileImageSizeOptions.php b/src/EventListener/DcGeneral/Table/RenderSetting/FileImageSizeOptions.php new file mode 100644 index 0000000..c6e04bb --- /dev/null +++ b/src/EventListener/DcGeneral/Table/RenderSetting/FileImageSizeOptions.php @@ -0,0 +1,90 @@ + + * @copyright 2012-2024 The MetaModels team. + * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later + * @filesource + */ + +declare(strict_types=1); + +namespace MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\RenderSetting; + +use ContaoCommunityAlliance\DcGeneral\Contao\RequestScopeDeterminator; +use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetPropertyOptionsEvent; +use Doctrine\DBAL\Connection; +use MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsProvider; +use MetaModels\CoreBundle\EventListener\DcGeneral\Table\RenderSetting\AbstractListener; +use MetaModels\IFactory; + +/** + * Add the options for the file image size. + */ +final class FileImageSizeOptions extends AbstractListener +{ + public function __construct( + RequestScopeDeterminator $scopeDeterminator, + IFactory $factory, + Connection $connection, + private readonly ImageSizeOptionsProvider $optionsProvider, + ) { + parent::__construct($scopeDeterminator, $factory, $connection); + } + + /** + * Invoke the event. + * + * @param GetPropertyOptionsEvent $event The event. + * + * @return void + */ + public function __invoke(GetPropertyOptionsEvent $event): void + { + if ( + ('file_imageSize' !== $event->getPropertyName()) + || (false === $this->wantToHandle($event)) + || (false === $this->isAttributeFile($event)) + ) { + return; + } + + $this->optionsProvider->addOptions($event); + } + + /** + * If used attribute type of file. + * + * @param GetPropertyOptionsEvent $event The event. + * + * @return bool + */ + private function isAttributeFile(GetPropertyOptionsEvent $event): bool + { + $builder = $this->connection->createQueryBuilder(); + $builder + ->select('t.type') + ->from('tl_metamodel_attribute', 't') + ->where($builder->expr()->eq('t.id', ':id')) + ->setParameter('id', $event->getModel()->getProperty('attr_id')); + + $statement = $builder->executeQuery(); + if (0 === $statement->columnCount()) { + return false; + } + + $result = $statement->fetchAssociative(); + + return 'file' === ($result['type'] ?? null); + } +} diff --git a/src/EventListener/HandleUpdateAttributeListener.php b/src/EventListener/HandleUpdateAttributeListener.php deleted file mode 100644 index a01702e..0000000 --- a/src/EventListener/HandleUpdateAttributeListener.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @author Sven Baumann - * @copyright 2012-2019 The MetaModels team. - * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later - * @filesource - */ - -namespace MetaModels\AttributeFileBundle\EventListener; - -use ContaoCommunityAlliance\DcGeneral\Event\PostPersistModelEvent; -use Doctrine\DBAL\Connection; -use MetaModels\Factory; -use MetaModels\Helper\TableManipulator; - -/** - * Class HandleUpdateAttributeListener - */ -class HandleUpdateAttributeListener extends BaseListener -{ - /** - * The doctrine dbal connection. - * - * @var Connection - */ - private $connection; - - /** - * The table manipulator. - * - * @var TableManipulator - */ - private $tableManipulator; - - /** - * HandleUpdateAttributeListener constructor. - * - * @param Factory $factory The attribute factory. - * @param Connection $connection The doctrine dbal connection. - * @param TableManipulator $tableManipulator The table manipulator. - */ - public function __construct(Factory $factory, Connection $connection, TableManipulator $tableManipulator) - { - parent::__construct($factory); - - $this->connection = $connection; - $this->tableManipulator = $tableManipulator; - } - - /** - * Handle the update of the file attribute, if switch on for file multiple. - * - * @param PostPersistModelEvent $event The event. - * - * @return void - * - * @throws \Exception If column not exist in the table. - */ - public function handleUpdateAttribute(PostPersistModelEvent $event) - { - $model = $event->getModel(); - - if (('file' !== $model->getProperty('type')) - || (!$model->getProperty('file_multiple')) - || ('tl_metamodel_attribute' !== $event->getEnvironment()->getDataDefinition()->getName()) - ) { - return; - } - - $metaModelsName = $this->getFactory()->translateIdToMetaModelName($model->getProperty('pid')); - $metaModel = $this->getFactory()->getMetaModel($metaModelsName); - $attributeName = $model->getProperty('colname') . '__sort'; - $tableColumns = $this->connection->getSchemaManager()->listTableColumns($metaModel->getTableName()); - - if (\array_key_exists($attributeName, $tableColumns)) { - return; - } - - $this->tableManipulator->createColumn($metaModel->getTableName(), $attributeName, 'blob NULL'); - } -} diff --git a/src/EventListener/ImageSizeOptionsListener.php b/src/EventListener/ImageSizeOptionsListener.php deleted file mode 100644 index cf8ed7b..0000000 --- a/src/EventListener/ImageSizeOptionsListener.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @author Christian Schiffler - * @copyright 2012-2019 The MetaModels team. - * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later - * @filesource - */ - -namespace MetaModels\AttributeFileBundle\EventListener; - -use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetPropertyOptionsEvent; -use ContaoCommunityAlliance\DcGeneral\Data\DefaultDataProvider; - -/** - * Get the options for the image size. - */ -class ImageSizeOptionsListener -{ - /** - * Get property options for file image size in the render settings. - * - * @param GetPropertyOptionsEvent $event The event. - * - * @return void - */ - public function getPropertyOptions(GetPropertyOptionsEvent $event) - { - if (('file_imageSize' !== $event->getPropertyName()) - || ('tl_metamodel_rendersetting' !== $event->getEnvironment()->getDataDefinition()->getName()) - ) { - return; - } - - $sizes = $this->getThemeImageSizes(); - if (!$sizes) { - return; - } - - $options = $event->getOptions(); - $options['image_sizes'] = \array_replace($sizes, (array) $options['image_sizes']); - - $event->setOptions($options); - } - - /** - * Get the image sizes from the theme. - * - * @return array - */ - private function getThemeImageSizes() - { - $dataProvider = new DefaultDataProvider(); - $dataProvider->setBaseConfig(['source' => 'tl_image_size']); - - $config = $dataProvider->getEmptyConfig(); - $config->setFields(['id', 'name', 'width', 'height']); - $config->setSorting(['pid', 'name']); - - $collection = $dataProvider->fetchAll($config); - if (!$collection->count()) { - return []; - } - - $sizes = []; - foreach ($collection as $model) { - $sizes[$model->getProperty('id')] = \sprintf( - '%s (%sx%s)', - $model->getProperty('name'), - $model->getProperty('width'), - $model->getProperty('height') - ); - } - - return $sizes; - } -} diff --git a/src/EventListener/ImageSizeOptionsProvider.php b/src/EventListener/ImageSizeOptionsProvider.php new file mode 100644 index 0000000..b1eae6e --- /dev/null +++ b/src/EventListener/ImageSizeOptionsProvider.php @@ -0,0 +1,82 @@ + + * @author Christian Schiffler + * @copyright 2012-2023 The MetaModels team. + * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later + * @filesource + */ + +namespace MetaModels\AttributeFileBundle\EventListener; + +use Contao\CoreBundle\Image\ImageSizes; +use ContaoCommunityAlliance\DcGeneral\Contao\View\Contao2BackendView\Event\GetPropertyOptionsEvent; +use Symfony\Contracts\Translation\TranslatorInterface; + +/** + * Get the options for the image size. + */ +class ImageSizeOptionsProvider +{ + public function __construct( + private readonly ImageSizes $imageSizes, + private readonly TranslatorInterface $translator, + ) { + } + + /** + * Add the options. + * + * @param GetPropertyOptionsEvent $event The event. + * + * @return void + */ + public function addOptions(GetPropertyOptionsEvent $event): void + { + $options = $this->imageSizes->getAllOptions(); + $optionsFull = []; + foreach ($options as $section => $sizeNames) { + $optionsFull[$this->translateSizeName($section)] = $this->translateSection($section, $sizeNames); + } + + $event->setOptions($optionsFull); + } + + private function translateSection(string $section, array $sizeNames): array + { + if (!\in_array($section, ['relative', 'exact'], true)) { + return $sizeNames; + } + + $optionSection = []; + foreach ($sizeNames as $currentLabel) { + $optionSection[$currentLabel] = $this->translateSizeName($currentLabel); + } + return $optionSection; + } + + private function translateSizeName(string $sizeName): string + { + $key = 'MSC.' . $sizeName . '.0'; + if ($key !== $label = $this->translator->trans($key, [], 'contao_default')) { + return $label; + } + $key = 'MSC.' . $sizeName; + if ($key !== $label = $this->translator->trans($key, [], 'contao_default')) { + return $label; + } + + return $sizeName; + } +} diff --git a/src/FileUsage/FileUsageProvider.php b/src/FileUsage/FileUsageProvider.php new file mode 100644 index 0000000..1b167a2 --- /dev/null +++ b/src/FileUsage/FileUsageProvider.php @@ -0,0 +1,177 @@ + + * @copyright 2012-2024 The MetaModels team. + * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later + * @filesource + */ + +namespace MetaModels\AttributeFileBundle\FileUsage; + +use Contao\CoreBundle\Csrf\ContaoCsrfTokenManager; +use Contao\FilesModel; +use Contao\Model\Collection; +use Contao\StringUtil; +use ContaoCommunityAlliance\DcGeneral\Data\ModelId; +use InspiredMinds\ContaoFileUsage\Provider\FileUsageProviderInterface; +use InspiredMinds\ContaoFileUsage\Result\ResultInterface; +use InspiredMinds\ContaoFileUsage\Result\ResultsCollection; +use MetaModels\AttributeFileBundle\Attribute\File; +use MetaModels\CoreBundle\FileUsage\MetaModelsMultipleResult; +use MetaModels\CoreBundle\FileUsage\MetaModelsSingleResult; +use MetaModels\IFactory; +use MetaModels\IMetaModel; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + +/** + * This class supports the Contao extension 'file usage'. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class FileUsageProvider implements FileUsageProviderInterface +{ + private string $refererId = ''; + + public function __construct( + private readonly IFactory $factory, + private readonly UrlGeneratorInterface $urlGenerator, + private readonly RequestStack $requestStack, + private readonly ContaoCsrfTokenManager $csrfTokenManager, + private readonly string $csrfTokenName, + ) { + } + + public function find(): ResultsCollection + { + $this->refererId = $this->requestStack->getCurrentRequest()?->attributes->get('_contao_referer_id') ?? ''; + + $allTables = $this->factory->collectNames(); + + $collection = new ResultsCollection(); + foreach ($allTables as $table) { + $collection->mergeCollection($this->processTable($table)); + } + + return $collection; + } + + private function processTable(string $table): ResultsCollection + { + $collection = new ResultsCollection(); + $metaModel = $this->factory->getMetaModel($table); + assert($metaModel instanceof IMetaModel); + + $allIds = $metaModel->getIdsFromFilter($metaModel->getEmptyFilter()); + foreach ($metaModel->getAttributes() as $attribute) { + if (!$attribute instanceof File) { + continue; + } + + $attributeName = $attribute->getColName(); + + $allData = $attribute->getDataFor($allIds); + if ($attribute->get('file_multiple')) { + foreach ($allData as $itemId => $selectedFiles) { + $collection->mergeCollection( + $this->addMultipleFileReferences($selectedFiles['value'], $table, $attributeName, $itemId) + ); + } + continue; + } + + foreach ($allData as $itemId => $selectedFiles) { + if ([] === $selectedFiles['value']) { + continue; + } + $collection->addResult( + $selectedFiles['value'][0], + $this->createFileResult($table, $attributeName, $itemId, false) + ); + } + } + + return $collection; + } + + private function addMultipleFileReferences( + array $fileUuids, + string $tableName, + string $attributeName, + string $itemId, + ): ResultsCollection { + $collection = new ResultsCollection(); + foreach ($fileUuids as $uuid) { + $collection->addResult($uuid, $this->createFileResult($tableName, $attributeName, $itemId, true)); + // Also add children, if the reference is a folder. + $file = FilesModel::findByUuid($uuid); + if (null !== $file && 'folder' === $file->type) { + $files = FilesModel::findByPid($uuid); + if (null === $files) { + continue; + } + assert($files instanceof Collection); + foreach ($files as $child) { + $collection->addResult( + StringUtil::binToUuid($child->uuid), + $this->createFileResult($tableName, $attributeName, $itemId, true) + ); + } + } + } + + return $collection; + } + + private function createFileResult( + string $tableName, + string $attributeName, + string $itemId, + bool $isMultiple + ): ResultInterface { + if ($isMultiple) { + return new MetaModelsMultipleResult( + $tableName, + $attributeName, + $itemId, + $this->urlGenerator->generate( + 'metamodels.metamodel', + [ + 'tableName' => $tableName, + 'act' => 'edit', + 'id' => ModelId::fromValues($tableName, $itemId)->getSerialized(), + 'ref' => $this->refererId, + 'rt' => $this->csrfTokenManager->getToken($this->csrfTokenName)->getValue(), + ] + ) + ); + } + + return new MetaModelsSingleResult( + $tableName, + $attributeName, + $itemId, + $this->urlGenerator->generate( + 'metamodels.metamodel', + [ + 'tableName' => $tableName, + 'act' => 'edit', + 'id' => ModelId::fromValues($tableName, $itemId)->getSerialized(), + 'ref' => $this->refererId, + 'rt' => $this->csrfTokenManager->getToken($this->csrfTokenName)->getValue(), + ] + ) + ); + } +} diff --git a/src/Migration/AddProtectedDownloadMigration.php b/src/Migration/AddProtectedDownloadMigration.php index 6f821f2..3e5d2d9 100644 --- a/src/Migration/AddProtectedDownloadMigration.php +++ b/src/Migration/AddProtectedDownloadMigration.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2022 The MetaModels team. + * (c) 2012-2023 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,7 +12,7 @@ * * @package MetaModels/attribute_file * @author Ingolf Steinhardt - * @copyright 2012-2022 The MetaModels team. + * @copyright 2012-2023 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -79,14 +79,16 @@ public function getName(): string */ public function shouldRun(): bool { - $schemaManager = $this->connection->getSchemaManager(); + $schemaManager = $this->connection->createSchemaManager(); if (!$schemaManager->tablesExist(['tl_metamodel', 'tl_metamodel_rendersetting'])) { return false; } - if ($this->fieldExists('tl_metamodel_rendersetting', 'file_showLink') - && !$this->fieldExists('tl_metamodel_rendersetting', 'file_protectedDownload')) { + if ( + $this->fieldExists('tl_metamodel_rendersetting', 'file_showLink') + && !$this->fieldExists('tl_metamodel_rendersetting', 'file_protectedDownload') + ) { return true; } @@ -111,7 +113,7 @@ public function run(): MigrationResult $this->connection->createQueryBuilder() ->update('tl_metamodel_rendersetting', 't') ->set('t.file_protectedDownload', 't.file_showLink') - ->execute(); + ->executeQuery(); return new MigrationResult(true, 'Adjusted table tl_metamodel_rendersetting with file_protectedDownload'); } @@ -129,7 +131,7 @@ public function run(): MigrationResult */ private function fieldExists(string $tableName, string $columnName): bool { - $columns = $this->connection->getSchemaManager()->listTableColumns($tableName); + $columns = $this->connection->createSchemaManager()->listTableColumns($tableName); return isset($columns[strtolower($columnName)]); } diff --git a/src/Migration/AddSortFieldMigration.php b/src/Migration/AddSortFieldMigration.php index 5a4b624..41534ce 100644 --- a/src/Migration/AddSortFieldMigration.php +++ b/src/Migration/AddSortFieldMigration.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2022 The MetaModels team. + * (c) 2012-2023 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,7 +13,7 @@ * @package MetaModels/attribute_file * @author Ingolf Steinhardt * @author Kim Wormer - * @copyright 2012-2022 The MetaModels team. + * @copyright 2012-2023 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -25,12 +25,13 @@ use Contao\CoreBundle\Migration\AbstractMigration; use Contao\CoreBundle\Migration\MigrationResult; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Exception; use Doctrine\DBAL\Result; use MetaModels\Helper\TableManipulator; /** * This migration add column *__sort for every - * file attribute column. + * file attribute column if option multiple set. */ class AddSortFieldMigration extends AbstractMigration { @@ -67,7 +68,7 @@ public function __construct(Connection $connection, TableManipulator $tableManip */ public function getName(): string { - return 'Add column *__sort for every file attribute column.'; + return 'Add column *__sort for every file attribute column if option multiple set.'; } /** @@ -76,10 +77,12 @@ public function getName(): string * - there are some columns defined * * @return bool + * + * @throws Exception */ public function shouldRun(): bool { - $schemaManager = $this->connection->getSchemaManager(); + $schemaManager = $this->connection->createSchemaManager(); if (!$schemaManager->tablesExist(['tl_metamodel', 'tl_metamodel_attribute'])) { return false; @@ -100,28 +103,40 @@ public function shouldRun(): bool * Create the missing columns *__sort for attribute file. * * @return MigrationResult + * + * @throws Exception */ public function run(): MigrationResult { $attributes = $this->getFileAttributes(); + $rows = $attributes->fetchAllAssociative(); - if (!$this->fieldExists('tl_metamodel_attribute', 'file_multiple') - && !$attributes->rowCount()) { + if ( + !$this->fieldExists('tl_metamodel_attribute', 'file_multiple') + && !$attributes->rowCount() + ) { return new MigrationResult(true, 'Nothing to do.'); } - while ($row = $attributes->fetchAssociative()) { + $messages = []; + foreach ($rows as $row) { if ($this->fieldExists($row['tableName'], $row['colname'] . '__sort')) { continue; } + $this->tableManipulator->createColumn( $row['tableName'], - $row['colname'], + $row['colname'] . '__sort', 'blob NULL' ); + + $messages[] = \sprintf('%s: %s__sort', $row['tableName'], $row['colname']); } - return new MigrationResult(true, 'Add columns *__sort at tl_metamodel_attribute for attribute file'); + return new MigrationResult( + true, + \sprintf('Add columns for attribute file: %s', \implode(', ', $messages)) + ); } /** @@ -131,19 +146,19 @@ public function run(): MigrationResult * * @throws \Doctrine\DBAL\Exception The DBAL exception. */ - private function getFileAttributes() + private function getFileAttributes(): Result { return $this ->connection ->createQueryBuilder() - ->select('metamodel.tableName', 'attribute.colname') + ->select('metamodel.tableName, attribute.colname') ->from('tl_metamodel_attribute', 'attribute') ->leftJoin('attribute', 'tl_metamodel', 'metamodel', 'metamodel.id=attribute.pid') ->where('attribute.type=:type') ->setParameter('type', 'file') ->andWhere('attribute.file_multiple=:multiple') ->setParameter('multiple', '1') - ->execute(); + ->executeQuery(); } /** @@ -152,14 +167,19 @@ private function getFileAttributes() * @param Result $attributes The attributes. * * @return int Returns columns count. + * + * @throws Exception */ - private function countMissingSortColumns($attributes): int + private function countMissingSortColumns(Result $attributes): int { $countColumns = 0; $rows = $attributes->fetchAllAssociative(); foreach ($rows as $row) { - if ($this->fieldExists($row['tableName'], $row['colname'] . '__sort')) { + if ( + !$this->fieldExists($row['tableName'], $row['colname']) + || $this->fieldExists($row['tableName'], $row['colname'] . '__sort') + ) { continue; } @@ -176,11 +196,13 @@ private function countMissingSortColumns($attributes): int * @param string $columnName Column name. * * @return bool + * + * @throws Exception */ private function fieldExists(string $tableName, string $columnName): bool { - $columns = $this->connection->getSchemaManager()->listTableColumns($tableName); + $columns = $this->connection->createSchemaManager()->listTableColumns($tableName); - return isset($columns[strtolower($columnName)]); + return isset($columns[\strtolower($columnName)]); } } diff --git a/src/Resources/config/event_listener.yml b/src/Resources/config/event_listener.yml index d797295..8ab2146 100644 --- a/src/Resources/config/event_listener.yml +++ b/src/Resources/config/event_listener.yml @@ -1,68 +1,79 @@ services: - metamodels.attribute_file.event_listener.image_size_options: - class: MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsListener - public: true - tags: - - name: kernel.event_listener - event: dc-general.view.contao2backend.get-property-options - method: getPropertyOptions + metamodels.attribute_file.event_listener.image_size_options: + class: MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsProvider + arguments: + $imageSizes: '@contao.image.sizes' + $translator: '@translator' - metamodels.attribute_file.event_listener.remove_type_options: - class: MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\Attribute\RemoveTypeOptions - public: true - tags: - - name: kernel.event_listener - event: dc-general.view.contao2backend.get-property-options - method: removeOption - priority: -1 + metamodels.attribute_file.event_listener.remove_type_options: + class: MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\Attribute\RemoveTypeOptions + public: true + tags: + - name: kernel.event_listener + event: dc-general.view.contao2backend.get-property-options + method: removeOption + priority: -1 - metamodels.attribute_file.event_listener.remove_attid_options: - class: MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\FilterSetting\RemoveAttIdOptions - public: true - tags: - - name: kernel.event_listener - event: dc-general.view.contao2backend.get-property-options - method: removeOption - priority: -1 + metamodels.attribute_file.event_listener.remove_attid_options: + class: MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\FilterSetting\RemoveAttIdOptions + public: true + tags: + - name: kernel.event_listener + event: dc-general.view.contao2backend.get-property-options + method: removeOption + priority: -1 - metamodels.attribute_file.event_listener.build_attribute: - class: MetaModels\AttributeFileBundle\EventListener\BuildAttributeListener - public: true - tags: - - name: kernel.event_listener - event: metamodels.dc-general.events.metamodel.build.attribute - method: buildAttribute + metamodels.attribute_file.event_listener.build_attribute: + class: MetaModels\AttributeFileBundle\EventListener\BuildAttributeListener + public: true + tags: + - name: kernel.event_listener + event: metamodels.dc-general.events.metamodel.build.attribute + method: buildAttribute - metamodels.attribute_file.event_listener.build-data-definition: - class: MetaModels\AttributeFileBundle\EventListener\BuildDataDefinitionListener - public: true - tags: - - name: kernel.event_listener - event: dc-general.factory.build-data-definition - method: buildDataDefinition - priority: 0 + metamodels.attribute_file.event_listener.build-data-definition: + class: MetaModels\AttributeFileBundle\EventListener\BuildDataDefinitionListener + public: true + tags: + - name: kernel.event_listener + event: dc-general.factory.build-data-definition + method: buildDataDefinition + priority: 0 - metamodels.attribute_file.event_listener.post-persist: - class: MetaModels\AttributeFileBundle\EventListener\HandleUpdateAttributeListener - arguments: - - "@metamodels.factory" - - "@database_connection" - - "@metamodels.table_manipulator" - public: true - tags: - - name: kernel.event_listener - event: dc-general.model.post-persist - method: handleUpdateAttribute - priority: -1 + MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\DcaSetting\FileWidgetModeOptions: + public: false + arguments: + $scopeDeterminator: '@cca.dc-general.scope-matcher' + $factory: '@MetaModels\IFactory' + $connection: '@database_connection' + # The $frontendEditing argument where set in the extension. + $frontendEditing: ~ + tags: + - name: kernel.event_listener + event: dc-general.view.contao2backend.get-property-options - MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\DcaSetting\FileWidgetModeOptions: - public: false - arguments: - $scopeDeterminator: '@cca.dc-general.scope-matcher' - $factory: '@MetaModels\IFactory' - $connection: '@database_connection' - # The $frontendEditing argument where set in the extension. - $frontendEditing: ~ - tags: - - name: kernel.event_listener - event: dc-general.view.contao2backend.get-property-options + MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\DcaSetting\FeeFileImageSizeOptions: + public: false + arguments: + $scopeDeterminator: '@cca.dc-general.scope-matcher' + $factory: '@MetaModels\IFactory' + $connection: '@database_connection' + $optionsProvider: '@metamodels.attribute_file.event_listener.image_size_options' + tags: + - name: kernel.event_listener + event: dc-general.view.contao2backend.get-property-options + + MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\RenderSetting\FileImageSizeOptions: + public: false + arguments: + $scopeDeterminator: '@cca.dc-general.scope-matcher' + $factory: '@MetaModels\IFactory' + $connection: '@database_connection' + $optionsProvider: '@metamodels.attribute_file.event_listener.image_size_options' + tags: + - name: kernel.event_listener + event: dc-general.view.contao2backend.get-property-options + + MetaModels\AttributeFileBundle\Schema\DoctrineSchemaGenerator: + tags: + - { name: 'metamodels.schema-generator.doctrine' } diff --git a/src/Resources/config/factory.yml b/src/Resources/config/factory.yml index b405e8e..fe9fcaa 100644 --- a/src/Resources/config/factory.yml +++ b/src/Resources/config/factory.yml @@ -4,7 +4,7 @@ services: arguments: - "@database_connection" - "@metamodels.table_manipulator" - - "@metamodels.attribute_file.toolbox.file" + - '@MetaModels\Helper\ToolboxFile' - "@=service('contao.framework').getAdapter('Contao\\\\StringUtil')" - "@=service('contao.framework').getAdapter('Contao\\\\Validator')" - "@=service('contao.framework').getAdapter('Contao\\\\FilesModel')" diff --git a/src/Resources/config/file_usage/services.yml b/src/Resources/config/file_usage/services.yml new file mode 100644 index 0000000..63e41d7 --- /dev/null +++ b/src/Resources/config/file_usage/services.yml @@ -0,0 +1,11 @@ +services: + MetaModels\AttributeFileBundle\FileUsage\FileUsageProvider: + public: true + arguments: + $factory: '@metamodels.factory' + $urlGenerator: '@router' + $requestStack: '@request_stack' + $csrfTokenManager: '@contao.csrf.token_manager' + $csrfTokenName: '%contao.csrf_token_name%' + tags: + - { name: contao_file_usage.provider } diff --git a/src/Resources/config/frontend_editing/event_listener.yml b/src/Resources/config/frontend_editing/event_listener.yml index 5feae68..5bdf9b5 100644 --- a/src/Resources/config/frontend_editing/event_listener.yml +++ b/src/Resources/config/frontend_editing/event_listener.yml @@ -8,9 +8,7 @@ services: arguments: - '@metamodels.view_combination' - '@security.token_storage' - - '@MetaModels\CoreBundle\Contao\InsertTag\ReplaceTableName' - - '@MetaModels\CoreBundle\Contao\InsertTag\ReplaceParam' - - '@database_connection' + - '@contao.insert_tag.parser' tags: - name: kernel.event_listener event: metamodels.dc-general.events.metamodel.build.attribute diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index 312f470..9c59da6 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -1,17 +1,20 @@ services: metamodels.attribute_file.toolbox.file: - deprecated: 'The "%alias_id%" service is deprecated. Use the "@MetaModels\Helper\ToolboxFile".' + deprecated: + package: metamodels /attribute_file + version: 2.1 + message: 'The "%alias_id%" service is deprecated. Use the "@MetaModels\Helper\ToolboxFile".' alias: MetaModels\Helper\ToolboxFile public: true metamodels.attribute_file.cache_system: - class: Doctrine\Common\Cache\FilesystemCache + class: Symfony\Component\Cache\Adapter\FilesystemAdapter public: false arguments: - "%metamodels.attribute_file.cache_dir%" metamodels.attribute_file.cache: - class: Cache\Adapter\Doctrine\DoctrineCachePool + class: Symfony\Component\Cache\Adapter\FilesystemAdapter public: false arguments: - "@metamodels.attribute_file.cache_system" diff --git a/src/Resources/contao/dca/tl_metamodel_attribute.php b/src/Resources/contao/dca/tl_metamodel_attribute.php index ff8b114..32a4fa3 100644 --- a/src/Resources/contao/dca/tl_metamodel_attribute.php +++ b/src/Resources/contao/dca/tl_metamodel_attribute.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2021 The MetaModels team. + * (c) 2012-2024 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,7 +17,7 @@ * @author David Molineus * @author Sven Baumann * @author Ingolf Steinhardt - * @copyright 2012-2021 The MetaModels team. + * @copyright 2012-2024 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -33,39 +33,48 @@ ]; $GLOBALS['TL_DCA']['tl_metamodel_attribute']['fields']['file_customFiletree'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_customFiletree'], - 'inputType' => 'checkbox', - 'sql' => 'char(1) NOT NULL default \'\'', - 'eval' => ['submitOnChange' => true, 'tl_class' => 'w50'] + 'label' => 'file_customFiletree.label', + 'description' => 'file_customFiletree.description', + 'inputType' => 'checkbox', + 'sql' => 'char(1) NOT NULL default \'\'', + 'eval' => ['submitOnChange' => true, 'tl_class' => 'w50'] ]; $GLOBALS['TL_DCA']['tl_metamodel_attribute']['fields']['file_multiple'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_multiple'], - 'inputType' => 'checkbox', - 'sql' => 'char(1) NOT NULL default \'\'', - 'eval' => ['tl_class' => 'w50'] + 'label' => 'file_multiple.label', + 'description' => 'file_multiple.description', + 'inputType' => 'checkbox', + 'sql' => 'char(1) NOT NULL default \'\'', + 'eval' => ['tl_class' => 'w50'] ]; $GLOBALS['TL_DCA']['tl_metamodel_attribute']['fields']['file_uploadFolder'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_uploadFolder'], - 'exclude' => true, - 'inputType' => 'fileTree', - 'sql' => 'blob NULL', - 'eval' => ['fieldType' => 'radio', 'tl_class' => 'clr'] + 'label' => 'file_uploadFolder.label', + 'description' => 'file_uploadFolder.description', + 'exclude' => true, + 'inputType' => 'fileTree', + 'sql' => 'blob NULL', + 'eval' => ['fieldType' => 'radio', 'tl_class' => 'clr'] ]; $GLOBALS['TL_DCA']['tl_metamodel_attribute']['fields']['file_validFileTypes'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_validFileTypes'], - 'inputType' => 'text', - 'sql' => 'varchar(255) NOT NULL default \'\'', - 'eval' => ['maxlength' => 255, 'tl_class' => 'w50'] + 'label' => 'file_validFileTypes.label', + 'description' => 'file_validFileTypes.description', + 'inputType' => 'text', + 'sql' => 'varchar(255) NOT NULL default \'\'', + 'eval' => ['maxlength' => 255, 'tl_class' => 'w50'] ]; $GLOBALS['TL_DCA']['tl_metamodel_attribute']['fields']['file_filesOnly'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_filesOnly'], - 'inputType' => 'select', - 'options' => ['', '1', '2'], - 'reference' => &$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_filesOnly_options'], - 'eval' => ['tl_class' => 'w50'], - 'sql' => ['type' => 'string', 'length' => 1, 'fixed' => true, 'default' => ''] + 'label' => 'file_filesOnly.label', + 'description' => 'file_filesOnly.description', + 'inputType' => 'select', + 'options' => ['', '1', '2'], + 'reference' => [ + '' => 'file_filesOnly_options.allow_both', + '1' => 'file_filesOnly_options.allow_files', + '2' => 'file_filesOnly_options.allow_folder', + ], + 'eval' => ['tl_class' => 'w50'], + 'sql' => ['type' => 'string', 'length' => 1, 'fixed' => true, 'default' => ''] ]; diff --git a/src/Resources/contao/dca/tl_metamodel_dcasetting.php b/src/Resources/contao/dca/tl_metamodel_dcasetting.php index d17e4ef..ba69c80 100644 --- a/src/Resources/contao/dca/tl_metamodel_dcasetting.php +++ b/src/Resources/contao/dca/tl_metamodel_dcasetting.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2022 The MetaModels team. + * (c) 2012-2024 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,35 +16,49 @@ * @author Andreas Isaak * @author Sven Baumann * @author Ingolf Steinhardt - * @copyright 2012-2022 The MetaModels team. + * @copyright 2012-2024 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ +use Contao\BackendUser; use Contao\System; use MetaModels\ContaoFrontendEditingBundle\MetaModelsContaoFrontendEditingBundle; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['metasubselectpalettes']['attr_id']['file'] = [ 'presentation' => [ - 'tl_class' + 'tl_class', + 'be_template', ], 'functions' => [ 'mandatory', 'file_widgetMode' + ], + 'overview' => [ + 'searchable', ] ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['file_widgetMode'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetMode'], - 'exclude' => true, - 'inputType' => 'radio', - 'default' => 'normal', - 'options' => ['normal'], - 'reference' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetModes'], - 'eval' => [ + 'label' => 'file_widgetMode.label', + 'description' => 'file_widgetMode.description', + 'exclude' => true, + 'inputType' => 'radio', + 'default' => 'normal', + 'options' => ['normal'], + 'reference' => [ + 'normal' => 'file_widgetModes.normal', + 'downloads' => 'file_widgetModes.downloads', + 'gallery' => 'file_widgetModes.gallery', + 'fe_single_upload' => 'file_widgetModes.fe_single_upload', + 'fe_single_upload_preview' => 'file_widgetModes.fe_single_upload_preview', + 'fe_multiple_upload' => 'file_widgetModes.fe_multiple_upload', + 'fe_multiple_upload_preview' => 'file_widgetModes.fe_multiple_upload_preview', + ], + 'eval' => [ 'tl_class' => 'clr w50' ], - 'sql' => 'char(32) NOT NULL default \'normal\'' + 'sql' => 'char(32) NOT NULL default \'normal\'' ]; // Load configuration for the frontend editing. @@ -53,6 +67,9 @@ System::getContainer()->getParameter('kernel.bundles'), true )) { + $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['metasubselectpalettes']['attr_id']['file']['presentation'][] = + 'fe_template'; + $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['file_widgetMode']['eval']['submitOnChange'] = true; $uploadSettings = [ @@ -92,128 +109,143 @@ ); $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_useHomeDir'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_useHomeDir'], - 'exclude' => true, - 'inputType' => 'checkbox', - 'eval' => [ + 'label' => 'fe_widget_file_useHomeDir.label', + 'description' => 'fe_widget_file_useHomeDir.description', + 'exclude' => true, + 'inputType' => 'checkbox', + 'eval' => [ 'tl_class' => 'w50 cbx m12', ], - 'sql' => "char(1) NOT NULL default ''", + 'sql' => "char(1) NOT NULL default ''", ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_uploadFolder'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_uploadFolder'], - 'exclude' => true, - 'inputType' => 'fileTree', - 'eval' => [ + 'label' => 'fe_widget_file_uploadFolder.label', + 'description' => 'fe_widget_file_uploadFolder.description', + 'exclude' => true, + 'inputType' => 'fileTree', + 'eval' => [ 'fieldType' => 'radio', 'tl_class' => 'w50' ], - 'sql' => "binary(16) NULL" + 'sql' => "binary(16) NULL" ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_doNotOverwrite'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_doNotOverwrite'], - 'exclude' => true, - 'inputType' => 'checkbox', - 'eval' => [ + 'label' => 'fe_widget_file_doNotOverwrite.label', + 'description' => 'fe_widget_file_doNotOverwrite.description', + 'exclude' => true, + 'inputType' => 'checkbox', + 'eval' => [ 'tl_class' => 'w50 cbx m12 clr', ], - 'sql' => "char(1) NOT NULL default ''", + 'sql' => "char(1) NOT NULL default ''", ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_deselect'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_deselect'], - 'exclude' => true, - 'inputType' => 'checkbox', - 'eval' => [ + 'label' => 'fe_widget_file_deselect.label', + 'description' => 'fe_widget_file_deselect.description', + 'exclude' => true, + 'inputType' => 'checkbox', + 'eval' => [ 'tl_class' => 'w50 clr cbx m12', ], - 'sql' => "char(1) NOT NULL default ''", + 'sql' => "char(1) NOT NULL default ''", ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_delete'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_delete'], - 'exclude' => true, - 'inputType' => 'checkbox', - 'eval' => [ + 'label' => 'fe_widget_file_delete.label', + 'description' => 'fe_widget_file_delete.description', + 'exclude' => true, + 'inputType' => 'checkbox', + 'eval' => [ 'tl_class' => 'w50 cbx m12', ], - 'sql' => "char(1) NOT NULL default ''", + 'sql' => "char(1) NOT NULL default ''", ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_extend_folder'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_extend_folder'], - 'inputType' => 'text', - 'eval' => [ + 'label' => 'fe_widget_file_extend_folder.label', + 'description' => 'fe_widget_file_extend_folder.description', + 'inputType' => 'text', + 'eval' => [ 'tl_class' => 'w50 clr' ], - 'sql' => "longtext" + 'sql' => "longtext" ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_normalize_extend_folder'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_normalize_extend_folder'], - 'exclude' => true, - 'inputType' => 'checkbox', - 'eval' => [ + 'label' => 'fe_widget_file_normalize_extend_folder.label', + 'description' => 'fe_widget_file_normalize_extend_folder.description', + 'exclude' => true, + 'inputType' => 'checkbox', + 'eval' => [ 'tl_class' => 'w50 cbx m12', ], - 'sql' => "char(1) NOT NULL default ''", + 'sql' => "char(1) NOT NULL default ''", ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_normalize_filename'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_normalize_filename'], - 'exclude' => true, - 'inputType' => 'checkbox', - 'eval' => [ + 'label' => 'fe_widget_file_normalize_filename.label', + 'description' => 'fe_widget_file_normalize_filename.description', + 'exclude' => true, + 'inputType' => 'checkbox', + 'eval' => [ 'tl_class' => 'w50 cbx m12', ], - 'sql' => "char(1) NOT NULL default ''", + 'sql' => "char(1) NOT NULL default ''", ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_prefix_filename'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_prefix_filename'], - 'inputType' => 'text', - 'eval' => [ + 'label' => 'fe_widget_file_prefix_filename.label', + 'description' => 'fe_widget_file_prefix_filename.description', + 'inputType' => 'text', + 'eval' => [ 'tl_class' => 'w50 clr' ], - 'sql' => "longtext" + 'sql' => "longtext" ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_postfix_filename'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_postfix_filename'], - 'inputType' => 'text', - 'eval' => [ + 'label' => 'fe_widget_file_postfix_filename.label', + 'description' => 'fe_widget_file_postfix_filename.description', + 'inputType' => 'text', + 'eval' => [ 'tl_class' => 'w50' ], - 'sql' => "longtext" + 'sql' => "longtext" ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_sortBy'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_sortBy'], - 'exclude' => true, - 'inputType' => 'select', - 'options' => ['name_asc', 'name_desc', 'date_asc', 'date_desc', 'random'], - 'reference' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting'], - 'sql' => 'varchar(32) NOT NULL default \'\'', - 'eval' => [ + 'label' => 'fe_widget_file_sortBy.label', + 'description' => 'fe_widget_file_sortBy.description', + 'exclude' => true, + 'inputType' => 'select', + 'options' => ['name_asc', 'name_desc', 'date_asc', 'date_desc', 'random'], + 'reference' => [ + 'name_asc' => 'fe_widget_file_sortBy.name_asc', + 'name_desc' => 'fe_widget_file_sortBy.name_desc', + 'date_asc' => 'fe_widget_file_sortBy.date_asc', + 'date_desc' => 'fe_widget_file_sortBy.date_desc', + 'random' => 'fe_widget_file_sortBy.random', + ], + 'sql' => 'varchar(32) NOT NULL default \'\'', + 'eval' => [ 'tl_class' => 'w50', 'chosen' => true ] ]; $GLOBALS['TL_DCA']['tl_metamodel_dcasetting']['fields']['fe_widget_file_imageSize'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_imageSize'], - 'exclude' => true, - 'inputType' => 'imageSize', - 'options' => $GLOBALS['TL_CROP'], - 'reference' => &$GLOBALS['TL_LANG']['MSC'], - 'sql' => 'varchar(255) NOT NULL default \'\'', - 'eval' => [ + 'label' => 'fe_widget_file_imageSize.label', + 'description' => 'fe_widget_file_imageSize.description', + 'exclude' => true, + 'inputType' => 'imageSize', + 'sql' => 'varchar(255) NOT NULL default \'\'', + 'eval' => [ 'rgxp' => 'digit', 'includeBlankOption' => true, 'nospace' => true, - 'helpwizard' => true, 'tl_class' => 'w50' ] ]; diff --git a/src/Resources/contao/dca/tl_metamodel_rendersetting.php b/src/Resources/contao/dca/tl_metamodel_rendersetting.php index 1919802..8eb74b0 100644 --- a/src/Resources/contao/dca/tl_metamodel_rendersetting.php +++ b/src/Resources/contao/dca/tl_metamodel_rendersetting.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2022 The MetaModels team. + * (c) 2012-2024 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,11 +16,15 @@ * @author Sven Baumann * @author Ingolf Steinhardt * @author Stefan Heimes - * @copyright 2012-2022 The MetaModels team. + * @author Cliff Parnitzky + * @copyright 2012-2024 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ +use Contao\BackendUser; +use Contao\System; + /** * Table tl_metamodel_rendersettings */ @@ -39,69 +43,79 @@ ]; $GLOBALS['TL_DCA']['tl_metamodel_rendersetting']['fields']['file_sortBy'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_sortBy'], - 'exclude' => true, - 'inputType' => 'select', - 'options' => ['name_asc', 'name_desc', 'date_asc', 'date_desc', 'manual', 'random'], - 'reference' => &$GLOBALS['TL_LANG']['tl_metamodel_rendersetting'], - 'sql' => 'varchar(32) NOT NULL default \'\'', - 'eval' => [ + 'label' => 'file_sortBy.label', + 'description' => 'file_sortBy.description', + 'exclude' => true, + 'inputType' => 'select', + 'options' => ['name_asc', 'name_desc', 'date_asc', 'date_desc', 'manual', 'random'], + 'reference' => [ + 'name_asc' => 'file_sortBy.name_asc', + 'name_desc' => 'file_sortBy.name_desc', + 'date_asc' => 'file_sortBy.date_asc', + 'date_desc' => 'file_sortBy.date_desc', + 'random' => 'file_sortBy.random', + 'manual' => 'file_sortBy.manual', + ], + 'sql' => 'varchar(32) NOT NULL default \'\'', + 'eval' => [ 'tl_class' => 'w50', 'chosen' => true ] ]; $GLOBALS['TL_DCA']['tl_metamodel_rendersetting']['fields']['file_showLink'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_showLink'], - 'inputType' => 'checkbox', - 'sql' => 'char(1) NOT NULL default \'\'', - 'eval' => [ + 'label' => 'file_showLink.label', + 'description' => 'file_showLink.description', + 'inputType' => 'checkbox', + 'sql' => 'char(1) NOT NULL default \'\'', + 'eval' => [ 'submitOnChange' => true, 'tl_class' => 'clr w50 cbx m12' ] ]; $GLOBALS['TL_DCA']['tl_metamodel_rendersetting']['fields']['file_protectedDownload'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_protectedDownload'], - 'inputType' => 'checkbox', - 'sql' => 'char(1) NOT NULL default \'\'', - 'eval' => [ + 'label' => 'file_protectedDownload.label', + 'description' => 'file_protectedDownload.description', + 'inputType' => 'checkbox', + 'sql' => 'char(1) NOT NULL default \'\'', + 'eval' => [ 'tl_class' => 'w50 cbx m12' ] ]; $GLOBALS['TL_DCA']['tl_metamodel_rendersetting']['fields']['file_showImage'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_showImage'], - 'inputType' => 'checkbox', - 'sql' => 'char(1) NOT NULL default \'\'', - 'eval' => [ + 'label' => 'file_showImage.label', + 'description' => 'file_showImage.description', + 'inputType' => 'checkbox', + 'sql' => 'char(1) NOT NULL default \'\'', + 'eval' => [ 'submitOnChange' => true, 'tl_class' => 'clr w50 cbx m12' ] ]; $GLOBALS['TL_DCA']['tl_metamodel_rendersetting']['fields']['file_imageSize'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_imageSize'], - 'exclude' => true, - 'inputType' => 'imageSize', - 'options' => $GLOBALS['TL_CROP'], - 'reference' => &$GLOBALS['TL_LANG']['MSC'], - 'sql' => 'varchar(255) NOT NULL default \'\'', - 'eval' => [ - 'rgxp' => 'digit', + 'label' => 'file_imageSize.label', + 'description' => 'file_imageSize.description', + 'exclude' => true, + 'inputType' => 'imageSize', + 'eval' => [ + 'rgxp' => 'natural', 'includeBlankOption' => true, 'nospace' => true, - 'helpwizard' => true, 'tl_class' => 'clr w50' - ] + ], + 'sql' => 'varchar(128) COLLATE ascii_bin NOT NULL default \'\'', ]; $GLOBALS['TL_DCA']['tl_metamodel_rendersetting']['fields']['file_placeholder'] = [ - 'label' => &$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_placeholder'], - 'exclude' => true, - 'inputType' => 'fileTree', - 'sql' => 'blob NULL', - 'eval' => [ + 'label' => 'file_placeholder.label', + 'description' => 'file_placeholder.description', + 'exclude' => true, + 'inputType' => 'fileTree', + 'sql' => 'blob NULL', + 'eval' => [ 'fieldType' => 'radio', 'files' => true, 'filesOnly' => true, diff --git a/src/Resources/contao/languages/de/default.php b/src/Resources/contao/languages/de/default.php deleted file mode 100644 index 25ba4bd..0000000 --- a/src/Resources/contao/languages/de/default.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @copyright 2012-2019 The MetaModels team. - * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later - * @filesource - */ - -$GLOBALS['TL_LANG']['ERR']['both_input_not_match'] = - 'The %s does not match the %s . Please check both entries.'; - diff --git a/src/Resources/contao/languages/en/tl_metamodel_attribute.php b/src/Resources/contao/languages/en/tl_metamodel_attribute.php deleted file mode 100644 index 9f70425..0000000 --- a/src/Resources/contao/languages/en/tl_metamodel_attribute.php +++ /dev/null @@ -1,45 +0,0 @@ - - * @author David Molineus - * @author Sven Baumann - * @author Ingolf Steinhardt - * @copyright 2012-2021 The MetaModels team. - * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later - * @filesource - */ - -// Fields. -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['typeOptions']['file'] = 'File'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_customFiletree'][0] = 'Customize the file tree'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_customFiletree'][1] = - 'Allows you to set custom options for the filetree.'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_uploadFolder'][0] = 'Set file root folder'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_uploadFolder'][1] = - 'Selects the root point from which the user will select this file field.'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_validFileTypes'][0] = 'Valid file types'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_validFileTypes'][1] = - 'To overwrite the contao standard file types, please enter a comma separated list of extensions of valid file ' . - 'types for this field.'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_filesOnly'][0] = 'Allowed types for selection'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_filesOnly'][1] = - 'Select a restriction on files or folders - default is no restriction on files or folders.'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_multiple'][0] = 'Multiple selection'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_multiple'][1] = - 'If selected, user will be able to select more than one item.'; - -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_filesOnly_options'][''] = 'Allow files and folders'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_filesOnly_options']['1'] = 'Allow files only'; -$GLOBALS['TL_LANG']['tl_metamodel_attribute']['file_filesOnly_options']['2'] = 'Allow folders only'; diff --git a/src/Resources/contao/languages/en/tl_metamodel_dcasetting.php b/src/Resources/contao/languages/en/tl_metamodel_dcasetting.php deleted file mode 100644 index 03ef83a..0000000 --- a/src/Resources/contao/languages/en/tl_metamodel_dcasetting.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @author Sven Baumann - * @author Ingolf Steinhardt - * @copyright 2012-2022 The MetaModels team. - * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0 - * @filesource - */ - -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetMode'][0] = 'Widget mode'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetMode'][1] = - 'With the mode the display type can be selected.'; - -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetModes']['normal'] = - 'Show files as list.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetModes']['downloads'] = - 'Show files as sortable file list e.g. for downloads.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetModes']['gallery'] = - 'Show files as sortable images e.g. for gallery.'; - -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetModes']['fe_single_upload'] = - 'Single file upload [only for frontend editing]'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetModes']['fe_single_upload_preview'] = - 'Single file upload with show thumbnail [only for frontend editing]'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetModes']['fe_multiple_upload'] = - 'Multiple file upload [only for frontend editing]'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['file_widgetModes']['fe_multiple_upload_preview'] = - 'Multiple file upload with show thumbnail [only for frontend editing]'; - -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_doNotOverwrite'][0] = 'Preserve existing files'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_doNotOverwrite'][1] = - 'Add a numeric suffix to the new file, if the file name already exists.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_useHomeDir'][0] = 'Use home directory'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_useHomeDir'][1] = - 'If this option is active, store the file in the home directory if there is an authenticated user. ' . - 'If the target folder configured too and the user is authenticated, so this folder is the base upload folder.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_uploadFolder'][0] = 'Target folder'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_uploadFolder'][1] = - 'Please select the target folder from the files directory. ' . - 'If the home dir configured too and is not authenticated a user, so this folder is the base folder.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_extend_folder'][0] = 'Extend folder'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_extend_folder'][1] = - 'Here you can extend the base upload folder path. The Contao insert tags are supported to extend the path. ' . - 'The insert tags from the custom sql filter work here too.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_deselect'][0] = 'Deselect file'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_deselect'][1] = - 'If this option deselect file is active, then that file entry is remove from this model.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_delete'][0] = 'Delete file'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_delete'][1] = - 'If this option delete file is active, then that file entry is remove from this model and from the file directory.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_normalize_extend_folder'][0] = 'Normalize extend folder'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_normalize_extend_folder'][1] = - 'Normalize the extend folder with an alias generator from the string util.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_normalize_filename'][0] = 'Normalize filename'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_normalize_filename'][1] = - 'Normalize the filename with an alias generator from the string util.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_prefix_filename'][0] = 'Prefix filename'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_prefix_filename'][1] = - 'Here you can prefix the filename. The Contao insert tags are supported to prefix the filename. ' . - 'The insert tags from the custom sql filter work here too.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_postfix_filename'][0] = 'Postfix filename'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_postfix_filename'][1] = - 'Here you can postfix the filename. The Contao insert tags are supported to postfix the filename. ' . - 'The insert tags from the custom sql filter work here too.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_imageSize'][0] = - 'Thumbnail width and height'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_imageSize'][1] = - 'Please enter either the image width, the image height or both measures to resize the image. If you leave both ' . - 'fields blank, the original image size will be displayed.'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_sortBy'][0] = 'Order by'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['fe_widget_file_sortBy'][1] = - 'Please choose the sort order.'; - -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['upload_settings_legend'] = 'File upload settings'; - -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['name_asc'] = 'File name (ascending)'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['name_desc'] = 'File name (descending)'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['date_asc'] = 'Date (ascending)'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['date_desc'] = 'Date (descending)'; -$GLOBALS['TL_LANG']['tl_metamodel_dcasetting']['random'] = 'Random order'; diff --git a/src/Resources/contao/languages/en/tl_metamodel_rendersetting.php b/src/Resources/contao/languages/en/tl_metamodel_rendersetting.php deleted file mode 100644 index 53ce8d1..0000000 --- a/src/Resources/contao/languages/en/tl_metamodel_rendersetting.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @author Sven Baumann - * @author Ingolf Steinhardt - * @copyright 2012-2022 The MetaModels team. - * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later - * @filesource - */ - -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_showImage'][0] = 'Enable as image field with thumbnail'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_showImage'][1] = - 'If selected, a thumbnail will be created for image files.'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_sortBy'][0] = 'Order by'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_sortBy'][1] = 'Please choose the sort order.'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_showLink'][0] = - 'Create link as file download or image lightbox'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_showLink'][1] = - 'Wraps the item in a link that will show the fullscreen image or download the file.'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_imageSize'][0] = 'Image width and height'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_imageSize'][1] = - 'Please enter either the image width, the image height or both measures to resize the image. If you leave both ' . - 'fields blank, the original image size will be displayed.'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_placeholder'][0] = 'Image placeholder'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_placeholder'][1] = - 'Select an image as a placeholder if no image is selected.'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_protectedDownload'][0] = 'Protected download'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['file_protectedDownload'][1] = - 'If this option is selected, the URL is only temporarily valid.'; - -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['name_asc'] = 'File name (ascending)'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['name_desc'] = 'File name (descending)'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['date_asc'] = 'Date (ascending)'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['date_desc'] = 'Date (descending)'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['random'] = 'Random order'; -$GLOBALS['TL_LANG']['tl_metamodel_rendersetting']['manual'] = 'Manual sorting'; diff --git a/src/Resources/contao/languages/et/tl_metamodel_attribute.php b/src/Resources/contao/languages/et/tl_metamodel_attribute.php deleted file mode 100644 index d154fd1..0000000 --- a/src/Resources/contao/languages/et/tl_metamodel_attribute.php +++ /dev/null @@ -1,19 +0,0 @@ -
  • settings->get('file_showImage')): ?> -
    style=""> +
    style=""> settings->get('file_showLink')): ?> diff --git a/src/Resources/contao/templates/mm_attr_file_alternative.html5 b/src/Resources/contao/templates/mm_attr_file_alternative.html5 index a476808..136da9c 100644 --- a/src/Resources/contao/templates/mm_attr_file_alternative.html5 +++ b/src/Resources/contao/templates/mm_attr_file_alternative.html5 @@ -2,7 +2,7 @@ src as $arrFile): ?>
    settings->get('file_showImage')): ?> -
    style=""> +
    style=""> settings->get('file_showLink')): ?> diff --git a/src/Resources/translations/tl_metamodel_attribute.de.xlf b/src/Resources/translations/tl_metamodel_attribute.de.xlf new file mode 100644 index 0000000..4f0a741 --- /dev/null +++ b/src/Resources/translations/tl_metamodel_attribute.de.xlf @@ -0,0 +1,62 @@ + + + + + File + Datei + + + Customize the file tree + Passen Sie den Dateibaum an + + + Allows you to set custom options for the filetree. + Erlaubt Ihnen, individuelle Optionen für den Dateibaum zu setzen. + + + Set file root folder + Wurzelordner (Root) angeben + + + Selects the root point from which the user will select this file field. + Wählen Sie den Punkt im Dateibaum, von dem aus Benutzer Daten hinzufügen können. + + + Valid file types + Gültige Dateitypen + + + To overwrite the contao standard file types, please enter a comma separated list of extensions of valid file types for this field. + Geben Sie hier eine kommagetrennte Liste gültiger Dateiendungen ein, um die Standard-Dateitypen von Contao zu überschreiben. + + + Allowed types for selection + Erlaubte Dateitypen + + + Select a restriction on files or folders - default is no restriction on files or folders. + Wählen Sie eine Einschränkung für Dateien oder Ordner aus - Standard ist keine Einschränkung für Dateien oder Ordner. + + + Multiple selection + Mehrfachauswahl + + + If selected, user will be able to select more than one item. + Wenn aktiviert, können mehrere Dateien ausgewählt werden. + + + Allow files and folders + Erlauben von Dateien und Ordnern + + + Allow files only + Nur Dateien erlauben + + + Allow folders only + Nur Ordner erlauben + + + + \ No newline at end of file diff --git a/src/Resources/translations/tl_metamodel_attribute.en.xlf b/src/Resources/translations/tl_metamodel_attribute.en.xlf new file mode 100644 index 0000000..539adb2 --- /dev/null +++ b/src/Resources/translations/tl_metamodel_attribute.en.xlf @@ -0,0 +1,49 @@ + + + + + + File + + + Customize the file tree + + + Allows you to set custom options for the filetree. + + + Set file root folder + + + Selects the root point from which the user will select this file field. + + + Valid file types + + + To overwrite the contao standard file types, please enter a comma separated list of extensions of valid file types for this field. + + + Allowed types for selection + + + Select a restriction on files or folders - default is no restriction on files or folders. + + + Multiple selection + + + If selected, user will be able to select more than one item. + + + Allow files and folders + + + Allow files only + + + Allow folders only + + + + diff --git a/src/Resources/translations/tl_metamodel_attribute.fr.xlf b/src/Resources/translations/tl_metamodel_attribute.fr.xlf new file mode 100644 index 0000000..26f346a --- /dev/null +++ b/src/Resources/translations/tl_metamodel_attribute.fr.xlf @@ -0,0 +1,62 @@ + + + + + File + Fichier + + + Customize the file tree + Personnaliser l'arborescence + + + Allows you to set custom options for the filetree. + Permet de personnaliser les options de l'arborescence. + + + Set file root folder + Spécifier le dossier racine + + + Selects the root point from which the user will select this file field. + Sélectionne le point racine à partir duquel l'utilisateur sélectionnera ce champ de fichier. + + + Valid file types + Types de fichiers autorisés + + + To overwrite the contao standard file types, please enter a comma separated list of extensions of valid file types for this field. + Saisir une liste d'extensions de fichiers séparées par des virgules pour remplacer les types standards définis dans Contao. + + + Allowed types for selection + Types autorisés à la sélection + + + Select a restriction on files or folders - default is no restriction on files or folders. + Définir une restriction de fichiers ou de dossiers. Par défaut, pas de restriction. + + + Multiple selection + Sélection multiple + + + If selected, user will be able to select more than one item. + Si coché, l'utilisateur pourra sélectionner plusieurs éléments. + + + Allow files and folders + Autoriser fichiers et dossiers + + + Allow files only + Autoriser seulement les fichiers + + + Allow folders only + Autoriser seulement les dossiers + + + + \ No newline at end of file diff --git a/src/Resources/translations/tl_metamodel_dcasetting.de.xlf b/src/Resources/translations/tl_metamodel_dcasetting.de.xlf new file mode 100644 index 0000000..1db9d43 --- /dev/null +++ b/src/Resources/translations/tl_metamodel_dcasetting.de.xlf @@ -0,0 +1,162 @@ + + + + + File upload settings + Einstellungen zum Upload von Dateien + + + Widget mode + Widget-Modus + + + With the mode the display type can be selected. + Mit dem Modus kann die Anzeigeart ausgewählt werden. + + + Preserve existing files + Vorhandene Dateien beibehalten + + + Add a numeric suffix to the new file, if the file name already exists. + Fügen Sie der neuen Datei ein numerisches Suffix hinzu, wenn der Dateiname bereits existiert. + + + Use home directory + Home-Verzeichnis verwenden + + + If this option is active, store the file in the home directory if there is an authenticated user. If the target folder configured too and the user is authenticated, so this folder is the base upload folder. + Wenn diese Option aktiv ist, wird die Datei im Home-Verzeichnis gespeichert, wenn es einen authentifizierten Benutzer gibt. Ist der Zielordner zu konfiguriert und der Benutzer ist authentifiziert, so ist dieser Ordner der Basis-Upload-Ordner. + + + Target folder + Zielordner + + + Please select the target folder from the files directory. If the home dir configured too and is not authenticated a user, so this folder is the base folder. + Bitte wählen Sie den Zielordner aus dem Dateiverzeichnis aus. Ist das Home-Verzeichnis konfiguriert und ein Benutzer nicht authentifiziert, so ist dieser Ordner der Basisordner. + + + Extend folder + Ordner erweitern + + + Here you can extend the base upload folder path. The Contao insert tags are supported to extend the path. + Hier können Sie den Basis-Upload-Ordnerpfad erweitern. Die Contao Insert-Tags werden unterstützt, um den Pfad zu erweitern. + + + Deselect file + Datei abwählen + + + If this option deselect file is active, then that file entry is remove from this model. + Wenn die Option Datei abwählen aktiviert ist, wird dieser Dateieintrag aus diesem Modell entfernt. + + + Delete file + Datei löschen + + + If this option delete file is active, then that file entry is remove from this model and from the file directory. + Ist die Option Datei löschen aktiv, so wird dieser Dateieintrag aus diesem Modell und aus dem Dateiverzeichnis entfernt. + + + Normalize extend folder + Erweiterten Ordner normalisieren + + + Normalize the extend folder with an alias generator from the string util. + Normalisieren Sie den erweiterten Ordner mit einem Alias-Generator. + + + Normalize filename + Dateinamen normalisieren + + + Normalize the filename with an alias generator from the string util. + Normalisieren Sie den Dateinamen mit einem Alias-Generator. + + + Prefix filename + Dateinamen Präfix + + + Here you can prefix the filename. The Contao insert tags are supported to prefix the filename. + Hier können Sie Zeichen den Dateinamen vorangestellt werden. Die Contao-Insert-Tags werden für das Voranstellen des Dateinamens unterstützt. + + + Postfix filename + Dateinamen Postfix + + + Here you can postfix the filename. The Contao insert tags are supported to postfix the filename. + Hier können Sie Zeichen den Dateinamen anhängen. Die Contao-Insert-Tags werden für das Voranstellen des Dateinamens unterstützt. + + + Thumbnail width and height + Breite und Höhe der Vorschaubilder + + + Please enter either the image width, the image height or both measures to resize the image. If you leave both fields blank, the original image size will be displayed. + Bitte geben Sie entweder die Bildbreite, die Bildhöhe oder beides ein, damit das Bild skaliert wird. Falls Sie beide Felder leer lassen, wird das Bild in Originalgröße ausgegeben. + + + Order by + Sortieren nach + + + Please choose the sort order. + Bitte wählen Sie die Sortierreihenfolge. + + + Show files as list. + Dateien als Liste anzeigen. + + + Show files as sortable file list e.g. for downloads. + Dateien als sortierbare Dateiliste anzeigen z.B. für Downloads. + + + Show files as sortable images e.g. for gallery. + Dateien als sortierbare Bilder anzeigen z.B. für eine Galerie. + + + Single file upload [only for frontend editing] + Einzelner Datei-Upload [nur für Frontend-Bearbeitung] + + + Single file upload with show thumbnail [only for frontend editing] + Einzelner Datei-Upload mit Anzeige der Vorschaubilder [nur für Frontend-Bearbeitung] + + + Multiple file upload [only for frontend editing] + Mehrfacher Datei-Upload [nur für Frontend-Bearbeitung] + + + Multiple file upload with show thumbnail [only for frontend editing] + Mehrfacher Datei-Upload mit Anzeige der Vorschaubilder [nur für Frontend-Bearbeitung] + + + File name (ascending) + Dateiname (aufsteigend) + + + File name (descending) + Dateiname (absteigend) + + + Date (ascending) + Datum (aufsteigend) + + + Date (descending) + Datum (absteigend) + + + Random order + Zufällige Reihenfolge + + + + diff --git a/src/Resources/translations/tl_metamodel_dcasetting.en.xlf b/src/Resources/translations/tl_metamodel_dcasetting.en.xlf new file mode 100644 index 0000000..51df50a --- /dev/null +++ b/src/Resources/translations/tl_metamodel_dcasetting.en.xlf @@ -0,0 +1,124 @@ + + + + + + File upload settings + + + Widget mode + + + With the mode the display type can be selected. + + + Preserve existing files + + + Add a numeric suffix to the new file, if the file name already exists. + + + Use home directory + + + If this option is active, store the file in the home directory if there is an authenticated user. If the target folder configured too and the user is authenticated, so this folder is the base upload folder. + + + Target folder + + + Please select the target folder from the files directory. If the home dir configured too and is not authenticated a user, so this folder is the base folder. + + + Extend folder + + + Here you can extend the base upload folder path. The Contao insert tags are supported to extend the path. + + + Deselect file + + + If this option deselect file is active, then that file entry is remove from this model. + + + Delete file + + + If this option delete file is active, then that file entry is remove from this model and from the file directory. + + + Normalize extend folder + + + Normalize the extend folder with an alias generator from the string util. + + + Normalize filename + + + Normalize the filename with an alias generator from the string util. + + + Prefix filename + + + Here you can prefix the filename. The Contao insert tags are supported to prefix the filename. + + + Postfix filename + + + Here you can postfix the filename. The Contao insert tags are supported to postfix the filename. + + + Thumbnail width and height + + + Please enter either the image width, the image height or both measures to resize the image. If you leave both fields blank, the original image size will be displayed. + + + Order by + + + Please choose the sort order. + + + Show files as list. + + + Show files as sortable file list e.g. for downloads. + + + Show files as sortable images e.g. for gallery. + + + Single file upload [only for frontend editing] + + + Single file upload with show thumbnail [only for frontend editing] + + + Multiple file upload [only for frontend editing] + + + Multiple file upload with show thumbnail [only for frontend editing] + + + File name (ascending) + + + File name (descending) + + + Date (ascending) + + + Date (descending) + + + Random order + + + + diff --git a/src/Resources/translations/tl_metamodel_dcasetting.fr.xlf b/src/Resources/translations/tl_metamodel_dcasetting.fr.xlf new file mode 100644 index 0000000..99f6282 --- /dev/null +++ b/src/Resources/translations/tl_metamodel_dcasetting.fr.xlf @@ -0,0 +1,162 @@ + + + + + File upload settings + Paramètres de transfert de fichiers + + + Widget mode + Mode du widget + + + With the mode the display type can be selected. + Le mode permet de sélectionner le type d'affichage. + + + Preserve existing files + Préserver les fichiers existants + + + Add a numeric suffix to the new file, if the file name already exists. + Ajouter un suffixe numérique au nouveau fichier si le nom de fichier existe déjà. + + + Use home directory + Utiliser le répertoire personnel + + + If this option is active, store the file in the home directory if there is an authenticated user. If the target folder configured too and the user is authenticated, so this folder is the base upload folder. + Enregistrer le fichier dans le dossier personnel de l'utilisateur s'il s'est authentifié. Si le dossier cible est également configuré et que l'utilisateur est authentifié, ce dossier est le dossier de téléchargement de base. + + + Target folder + Dossier cible + + + Please select the target folder from the files directory. If the home dir configured too and is not authenticated a user, so this folder is the base folder. + Sélectionner un dossier cible dans le répertoire des fichiers. Si un répertoire personnel est configuré mais que l'utilisateur n'est pas authentifié, ce dossier sera le dossier de base. + + + Extend folder + Étendre le chemin du dossier + + + Here you can extend the base upload folder path. The Contao insert tags are supported to extend the path. + Ici vous pouvez étendre le chemin du dossier de téléchargement de base. Les insert tags de Contao sont supportés. + + + Deselect file + Désélectionner le fichier + + + If this option deselect file is active, then that file entry is remove from this model. + Si cette option est active, cette entrée de fichier sera supprimée de ce modèle. + + + Delete file + Supprimer le fichier + + + If this option delete file is active, then that file entry is remove from this model and from the file directory. + Si cette option est active, cette entrée de fichier sera supprimée de ce modèle et du dossier. + + + Normalize extend folder + Normaliser l'extension du chemin du dossier + + + Normalize the extend folder with an alias generator from the string util. + Normaliser l'extension de dossier avec un générateur d'alias à partir de la chaîne util. + + + Normalize filename + Normaliser le nom de fichier. + + + Normalize the filename with an alias generator from the string util. + Normaliser le nom de fichier avec un générateur d'alias à partir de la chaîne util. + + + Prefix filename + Préfixe de nom de fichier + + + Here you can prefix the filename. The Contao insert tags are supported to prefix the filename. + Ajouter un préfixe aux noms de fichiers. Les insert tags de Contao peuvent être utilisés. + + + Postfix filename + Suffixe de nom de fichier + + + Here you can postfix the filename. The Contao insert tags are supported to postfix the filename. + Ajouter un postfixe aux noms de fichiers. Les insert tags de Contao peuvent être utilisés. + + + Thumbnail width and height + Hauteur et largeur de la vignette + + + Please enter either the image width, the image height or both measures to resize the image. If you leave both fields blank, the original image size will be displayed. + Indiquer la largeur de l'image, sa hauteur ou les deux pour la redimensionner. Si les deux champs sont vides, l'image s'affichera à sa taille originale. + + + Order by + Classer + + + Please choose the sort order. + Sélectionner l'ordre de classement. + + + Show files as list. + Afficher les fichiers en liste + + + Show files as sortable file list e.g. for downloads. + Afficher les fichiers sous forme de liste à classer (ex : pour des téléchargements) + + + Show files as sortable images e.g. for gallery. + Afficher les fichiers sous forme d'images à classer (ex : pour une galerie) + + + Single file upload [only for frontend editing] + Télécharger un fichier unique [réservé à l'édition en frontend] + + + Single file upload with show thumbnail [only for frontend editing] + Télécharger un fichier unique avec la vignette [réservé à l'édition en frontend] + + + Multiple file upload [only for frontend editing] + Téléchargment multiple [pour l'édition en frontend] + + + Multiple file upload with show thumbnail [only for frontend editing] + Téléchargment multiple avec vignette [pour l'édition en frontend] + + + File name (ascending) + Nom de fichier (ascendant) + + + File name (descending) + Nom de fichier (descendant) + + + Date (ascending) + Date (ascendante) + + + Date (descending) + Date (descendante) + + + Random order + Ordre aléatoire + + + + \ No newline at end of file diff --git a/src/Resources/translations/tl_metamodel_rendersetting.de.xlf b/src/Resources/translations/tl_metamodel_rendersetting.de.xlf new file mode 100644 index 0000000..0c45624 --- /dev/null +++ b/src/Resources/translations/tl_metamodel_rendersetting.de.xlf @@ -0,0 +1,78 @@ + + + + + Enable as image field with thumbnail + Als Bildfeld mit Vorschaubild benutzen + + + If selected, a thumbnail will be created for image files. + Falls aktiviert, wird für das Bild ein verkleinertes Vorschaubild generiert. + + + Order by + Sortierung nach + + + Please choose the sort order. + Bitte wählen Sie die Sortierreihenfolge. + + + Create link as file download or image lightbox + Link als Download oder Lightbox erstellen + + + Wraps the item in a link that will show the fullscreen image or download the file. + Das Item wird in einen Link eingebettet, der entweder für eine Großansicht oder einen Download dienen kann. + + + Image width and height + Bildbreite und -höhe + + + Please enter either the image width, the image height or both measures to resize the image. If you leave both fields blank, the original image size will be displayed. + Bitte geben Sie entweder die Bildbreite, die Bildhöhe oder beides ein, damit das Bild skaliert wird. Falls Sie beide Felder leer lassen, wird das Bild in Originalgröße ausgegeben. + + + Image placeholder + Bild als Platzhalter + + + Select an image as a placeholder if no image is selected. + Wählen Sie ein Bild als Platzhalter, wenn kein Bild ausgewählt ist. + + + Protected download + Geschützter Download + + + If this option is selected, the URL is only temporarily valid. + Wenn diese Option ausgewählt ist, ist die URL nur vorübergehend gültig. + + + File name (ascending) + Dateiname (aufsteigend) + + + File name (descending) + Dateiname (absteigend) + + + Date (ascending) + Datum (aufsteigend) + + + Date (descending) + Datum (absteigend) + + + Random order + Zufällige Reihenfolge + + + Manual sorting + Manuelle Sortierung + + + + \ No newline at end of file diff --git a/src/Resources/translations/tl_metamodel_rendersetting.en.xlf b/src/Resources/translations/tl_metamodel_rendersetting.en.xlf new file mode 100644 index 0000000..93ad4b4 --- /dev/null +++ b/src/Resources/translations/tl_metamodel_rendersetting.en.xlf @@ -0,0 +1,61 @@ + + + + + + Enable as image field with thumbnail + + + If selected, a thumbnail will be created for image files. + + + Order by + + + Please choose the sort order. + + + Create link as file download or image lightbox + + + Wraps the item in a link that will show the fullscreen image or download the file. + + + Image width and height + + + Please enter either the image width, the image height or both measures to resize the image. If you leave both fields blank, the original image size will be displayed. + + + Image placeholder + + + Select an image as a placeholder if no image is selected. + + + Protected download + + + If this option is selected, the URL is only temporarily valid. + + + File name (ascending) + + + File name (descending) + + + Date (ascending) + + + Date (descending) + + + Random order + + + Manual sorting + + + + diff --git a/src/Resources/translations/tl_metamodel_rendersetting.fr.xlf b/src/Resources/translations/tl_metamodel_rendersetting.fr.xlf new file mode 100644 index 0000000..203eb64 --- /dev/null +++ b/src/Resources/translations/tl_metamodel_rendersetting.fr.xlf @@ -0,0 +1,78 @@ + + + + + Enable as image field with thumbnail + Gérer comme image avec vignette + + + If selected, a thumbnail will be created for image files. + Cocher pour créer une vignette pour les fichiers image. + + + Order by + Classer par + + + Please choose the sort order. + Choisir l'ordre de classement. + + + Create link as file download or image lightbox + Créer un lien de téléchargement ou une image lightbox. + + + Wraps the item in a link that will show the fullscreen image or download the file. + Enveloppe l'élément dans un lien qui affichera l'image en plein écran ou téléchargera le fichier. + + + Image width and height + Largeur et hauteur de l'image + + + Please enter either the image width, the image height or both measures to resize the image. If you leave both fields blank, the original image size will be displayed. + Indiquer la largeur, la hauteur ou les deux pour redimensionner l'image. Si les deux sont vides, l'image sera affichée en taille originale. + + + Image placeholder + Image de remplacement + + + Select an image as a placeholder if no image is selected. + Sélectionner une image de remplacement tant qu'aucune image n'est sélectionnée. + + + Protected download + Téléchargement sécurisé + + + If this option is selected, the URL is only temporarily valid. + Si l'option est sélectionnée, l'url sera temporaire. + + + File name (ascending) + Nom de fichier (ascendant) + + + File name (descending) + Nom de fichier (descendant) + + + Date (ascending) + Date (ascendante) + + + Date (descending) + Date (descendante) + + + Random order + Ordre aléatoire + + + Manual sorting + Ordre manuel + + + + \ No newline at end of file diff --git a/src/Schema/DoctrineSchemaGenerator.php b/src/Schema/DoctrineSchemaGenerator.php new file mode 100644 index 0000000..fb045a6 --- /dev/null +++ b/src/Schema/DoctrineSchemaGenerator.php @@ -0,0 +1,60 @@ + + * @author Ingolf Steinhardt + * @copyright 2012-2022 The MetaModels team. + * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later + * @filesource + */ + +declare(strict_types=1); + +namespace MetaModels\AttributeFileBundle\Schema; + +use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\Types; +use MetaModels\Information\AttributeInformation; +use MetaModels\Schema\Doctrine\AbstractAttributeTypeSchemaGenerator; + +/** + * This adds all alias columns to doctrine tables schemas. + */ +class DoctrineSchemaGenerator extends AbstractAttributeTypeSchemaGenerator +{ + /** + * {@inheritDoc} + */ + protected function getTypeName(): string + { + return 'file'; + } + + /** + * {@inheritDoc} + */ + protected function generateAttribute(Table $tableSchema, AttributeInformation $attribute): void + { + $this->setColumnData($tableSchema, $attribute->getName(), Types::BLOB, [ + 'notnull' => false, + 'length' => 65535, + ]); + + if ($attribute->getConfigurationValue('file_multiple')) { + $this->setColumnData($tableSchema, $attribute->getName() . '__sort', Types::BLOB, [ + 'notnull' => false, + 'length' => 65535, + ]); + } + } +} diff --git a/src/deprecated-autoload.php b/src/deprecated-autoload.php index 4085698..7a050dc 100644 --- a/src/deprecated-autoload.php +++ b/src/deprecated-autoload.php @@ -23,7 +23,7 @@ use MetaModels\AttributeFileBundle\Attribute\File; use MetaModels\AttributeFileBundle\Attribute\FileOrder; use MetaModels\AttributeFileBundle\DcGeneral\AttributeFileDefinition; -use MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsListener; +use MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsProvider; // This hack is to load the "old locations" of the classes. spl_autoload_register( @@ -33,7 +33,7 @@ function ($class) { 'MetaModels\Attribute\File\FileOrder' => FileOrder::class, 'MetaModels\Attribute\File\AttributeTypeFactory' => AttributeTypeFactory::class, 'MetaModels\DcGeneral\AttributeFileDefinition' => AttributeFileDefinition::class, - 'MetaModels\Events\Attribute\File\ImageSizeOptions' => ImageSizeOptionsListener::class + 'MetaModels\Events\Attribute\File\ImageSizeOptions' => ImageSizeOptionsProvider::class ]; if (isset($classes[$class])) { diff --git a/tests/Attribute/FileAttributeTypeFactoryTest.php b/tests/Attribute/FileAttributeTypeFactoryTest.php index b9683c5..a5d1bd1 100644 --- a/tests/Attribute/FileAttributeTypeFactoryTest.php +++ b/tests/Attribute/FileAttributeTypeFactoryTest.php @@ -47,9 +47,7 @@ class FileAttributeTypeFactoryTest extends TestCase * Mock a MetaModel. * * @param string $tableName The table name. - * * @param string $language The language. - * * @param string $fallbackLanguage The fallback language. * * @return IMetaModel @@ -89,8 +87,8 @@ private function mockConnection(AbstractSchemaManager $schemaManager = null) $connection ->expects(self::any()) - ->method('getSchemaManager') - ->willReturn($schemaManager); + ->method('createSchemaManager') + ->willReturn($schemaManager ?? $this->mockSchemaManager()); return $connection; } diff --git a/tests/Attribute/FileTest.php b/tests/Attribute/FileTest.php index 7c07acb..d434ff5 100644 --- a/tests/Attribute/FileTest.php +++ b/tests/Attribute/FileTest.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2022 The MetaModels team. + * (c) 2012-2024 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,7 +15,7 @@ * @author David Greminger * @author Sven Baumann * @author Ingolf Steinhardt - * @copyright 2012-2022 The MetaModels team. + * @copyright 2012-2024 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -24,10 +24,12 @@ use Contao\CoreBundle\Framework\Adapter; use Contao\CoreBundle\Image\ImageFactoryInterface; +use Contao\StringUtil; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Query\Expression\ExpressionBuilder; use Doctrine\DBAL\Query\QueryBuilder; -use Doctrine\DBAL\Statement; +use Doctrine\DBAL\Result; use MetaModels\AttributeFileBundle\Attribute\File; use MetaModels\Helper\TableManipulator; use MetaModels\Helper\ToolboxFile; @@ -39,6 +41,8 @@ * Unit tests to test class File. * * @covers \MetaModels\AttributeFileBundle\Attribute\File + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class FileTest extends TestCase { @@ -46,7 +50,6 @@ class FileTest extends TestCase * Mock a MetaModel. * * @param string $tableName The table name. - * * @param string $language The language. * * @return IMetaModel @@ -77,10 +80,19 @@ protected function mockMetaModel($tableName, $language) */ private function mockConnection($methods = []) { - return $this->getMockBuilder(Connection::class) + $connection = $this->getMockBuilder(Connection::class) ->disableOriginalConstructor() - ->setMethods($methods) + ->onlyMethods(\array_merge($methods, ['getDatabasePlatform'])) ->getMock(); + + $platform = $this + ->getMockBuilder(AbstractPlatform::class) + ->disableOriginalConstructor() + ->onlyMethods([]) + ->getMockForAbstractClass(); + $connection->method('getDatabasePlatform')->willReturn($platform); + + return $connection; } /** @@ -101,6 +113,8 @@ private function mockTableManipulator(Connection $connection) * Mock the image factory. * * @return ImageFactoryInterface|MockObject + * + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ private function mockImageFactory() { @@ -205,47 +219,76 @@ public function testEmptyValues() ); self::assertEquals( ['bin' => [], 'value' => [], 'path' => [], 'meta' => []], - $file->widgetToValue(array(), 1) + $file->widgetToValue([], 1) ); } /** - * Test the search for method. - * - * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function testSearchFor() + public function testSearchForFileName() { - $metaModel = $this->mockMetaModel('mm_test', 'en'); - $connection = $this->mockConnection(['createQueryBuilder']); - $manipulator = $this->mockTableManipulator($connection); + $metaModel = $this->mockMetaModel('mm_test', 'en'); + $connection = $this->mockConnection(['createQueryBuilder']); + $manipulator = $this->mockTableManipulator($connection); - $statement = $this - ->getMockBuilder(Statement::class) + $result1 = $this + ->getMockBuilder(Result::class) ->disableOriginalConstructor() - ->setMethods(['fetchAll']) + ->onlyMethods(['fetchAllAssociative']) ->getMock(); - $statement + $result1 ->expects(self::once()) - ->method('fetchAll') - ->with(\PDO::FETCH_COLUMN) - ->willReturn(['1', '2', '3', '4', '5']); + ->method('fetchAllAssociative') + ->willReturn( + [ + [ + 'pid' => StringUtil::uuidToBin('b4a3201a-bef2-153c-85ae-66930f01feda'), + 'uuid' => StringUtil::uuidToBin('e68feb56-339b-1eb2-a675-7a5107362e40'), + ], + [ + 'pid' => StringUtil::uuidToBin('b4a3201a-bef2-153c-85ae-66930f01feda'), + 'uuid' => StringUtil::uuidToBin('6e38171a-47c3-1e91-83b4-b759ede063be'), + ], + [ + 'pid' => StringUtil::uuidToBin('314f23ae-30ce-11bb-bbd3-2009656507f7'), + 'uuid' => StringUtil::uuidToBin('0e9e4236-2468-1bfa-89f8-ca45602bec2a'), + ], + ] + ); $builder1 = $this ->getMockBuilder(QueryBuilder::class) - ->disableOriginalConstructor() - ->setMethods(['expr']) + ->setConstructorArgs([$connection]) + ->onlyMethods(['executeQuery', 'expr']) ->getMock(); $builder1->expects(self::once())->method('expr')->willReturn(new ExpressionBuilder($connection)); + $builder1 + ->expects(self::once()) + ->method('executeQuery') + ->willReturn($result1); + + $result2 = $this + ->getMockBuilder(Result::class) + ->disableOriginalConstructor() + ->onlyMethods(['fetchFirstColumn']) + ->getMock(); + $result2 + ->expects(self::once()) + ->method('fetchFirstColumn') + ->willReturn([1, 2, 3, 4, 5]); $builder2 = $this ->getMockBuilder(QueryBuilder::class) - ->disableOriginalConstructor() - ->setMethods(['execute', 'expr']) + ->setConstructorArgs([$connection]) + ->onlyMethods(['executeQuery']) ->getMock(); - $builder2->expects(self::once())->method('expr')->willReturn(new ExpressionBuilder($connection)); - $builder2->expects(self::once())->method('execute')->willReturn($statement); + + $builder2 + ->expects(self::once()) + ->method('executeQuery') + ->willReturn($result2); $connection ->expects(self::exactly(2)) @@ -269,11 +312,135 @@ public function testSearchFor() self::assertSame(['1', '2', '3', '4', '5'], $file->searchFor('*test?value')); - /** @var QueryBuilder $builder2 */ self::assertSame( - 'SELECT t.id FROM mm_test t WHERE file_attribute IN (SELECT f.uuid FROM tl_files f WHERE f.path LIKE :value)', + 'SELECT f.uuid, f.pid FROM tl_files f WHERE f.name LIKE :value', + $builder1->getSQL() + ); + self::assertSame(['value' => '%test_value'], $builder1->getParameters()); + + self::assertSame( + 'SELECT t.id FROM mm_test t WHERE ' . + '(t.file_attribute LIKE :value_0)' . + ' OR (t.file_attribute LIKE :value_1)' . + ' OR (t.file_attribute LIKE :value_2)' . + ' OR (t.file_attribute LIKE :value_3)' . + ' OR (t.file_attribute LIKE :value_4)', $builder2->getSQL() ); - self::assertSame(['value' => '%test_value'], $builder2->getParameters()); + self::assertSame( + [ + 'value_0' => '%' . StringUtil::uuidToBin('b4a3201a-bef2-153c-85ae-66930f01feda') . '%', + 'value_1' => '%' . StringUtil::uuidToBin('e68feb56-339b-1eb2-a675-7a5107362e40') . '%', + 'value_2' => '%' . StringUtil::uuidToBin('6e38171a-47c3-1e91-83b4-b759ede063be') . '%', + 'value_3' => '%' . StringUtil::uuidToBin('314f23ae-30ce-11bb-bbd3-2009656507f7') . '%', + 'value_4' => '%' . StringUtil::uuidToBin('0e9e4236-2468-1bfa-89f8-ca45602bec2a') . '%', + ], + $builder2->getParameters() + ); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testSearchForUuid() + { + $metaModel = $this->mockMetaModel('mm_test', 'en'); + $connection = $this->mockConnection(['createQueryBuilder']); + $manipulator = $this->mockTableManipulator($connection); + + $result1 = $this + ->getMockBuilder(Result::class) + ->disableOriginalConstructor() + ->onlyMethods(['fetchAllAssociative']) + ->getMock(); + $result1 + ->expects(self::once()) + ->method('fetchAllAssociative') + ->willReturn( + [ + [ + 'pid' => StringUtil::uuidToBin('b4a3201a-bef2-153c-85ae-66930f01feda'), + 'uuid' => StringUtil::uuidToBin('e68feb56-339b-1eb2-a675-7a5107362e40'), + ], + ] + ); + + $builder1 = $this + ->getMockBuilder(QueryBuilder::class) + ->setConstructorArgs([$connection]) + ->onlyMethods(['executeQuery']) + ->getMock(); + + $builder1 + ->expects(self::once()) + ->method('executeQuery') + ->willReturn($result1); + + $result2 = $this + ->getMockBuilder(Result::class) + ->disableOriginalConstructor() + ->onlyMethods(['fetchFirstColumn']) + ->getMock(); + $result2 + ->expects(self::once()) + ->method('fetchFirstColumn') + ->willReturn([1, 2, 3, 4, 5]); + + $builder2 = $this + ->getMockBuilder(QueryBuilder::class) + ->setConstructorArgs([$connection]) + ->onlyMethods(['executeQuery']) + ->getMock(); + + $builder2 + ->expects(self::once()) + ->method('executeQuery') + ->willReturn($result2); + + $connection + ->expects(self::exactly(2)) + ->method('createQueryBuilder') + ->willReturnOnConsecutiveCalls($builder1, $builder2); + + $file = new File( + $metaModel, + [ + 'colname' => 'file_attribute', + 'file_multiple' => false + ], + $connection, + $manipulator, + $this->mockToolboxFile(), + $this->mockStringUtil(), + $this->mockValidator(), + $this->mockFileRepository(), + $this->mockConfig() + ); + + self::assertSame(['1', '2', '3', '4', '5'], $file->searchFor('*e68feb56-339b-1eb2-a675-7a5107362e40*')); + + self::assertSame( + ['value' => StringUtil::uuidToBin('e68feb56-339b-1eb2-a675-7a5107362e40')], + $builder1->getParameters() + ); + self::assertSame( + 'SELECT f.uuid, f.pid FROM tl_files f WHERE f.uuid = :value', + $builder1->getSQL() + ); + + self::assertSame( + 'SELECT t.id FROM mm_test t WHERE ' . + '(t.file_attribute LIKE :value_0)' . + ' OR (t.file_attribute LIKE :value_1)', + $builder2->getSQL() + ); + + self::assertSame( + [ + 'value_0' => '%' . StringUtil::uuidToBin('b4a3201a-bef2-153c-85ae-66930f01feda') . '%', + 'value_1' => '%' . StringUtil::uuidToBin('e68feb56-339b-1eb2-a675-7a5107362e40') . '%', + ], + $builder2->getParameters() + ); } } diff --git a/tests/DependencyInjection/MetaModelsAttributeFileExtensionTest.php b/tests/DependencyInjection/MetaModelsAttributeFileExtensionTest.php index 76758f5..02b795d 100644 --- a/tests/DependencyInjection/MetaModelsAttributeFileExtensionTest.php +++ b/tests/DependencyInjection/MetaModelsAttributeFileExtensionTest.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2021 The MetaModels team. + * (c) 2012-2024 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,16 +13,21 @@ * @package MetaModels/attribute_file * @author Christian Schiffler * @author Sven Baumann - * @copyright 2012-2021 The MetaModels team. + * @author Ingolf Steinhardt + * @copyright 2012-2024 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ namespace MetaModels\AttributeFileBundle\Test\DependencyInjection; -use MetaModels\AttributeFileBundle\Attribute\AttributeTypeFactory; use MetaModels\AttributeFileBundle\DependencyInjection\MetaModelsAttributeFileExtension; +use MetaModels\AttributeFileBundle\EventListener\DcGeneral\Table\DcaSetting\FileWidgetModeOptions; use MetaModels\ContaoFrontendEditingBundle\MetaModelsContaoFrontendEditingBundle; +use MetaModels\AttributeFileBundle\EventListener\BuildAttributeListener; +use MetaModels\AttributeFileBundle\EventListener\BuildDataDefinitionListener; +use MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsProvider; +use MetaModels\AttributeFileBundle\Schema\DoctrineSchemaGenerator; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; @@ -35,12 +40,7 @@ */ class MetaModelsAttributeFileExtensionTest extends TestCase { - /** - * Test that extension can be instantiated. - * - * @return void - */ - public function testInstantiation() + public function testInstantiation(): void { $extension = new MetaModelsAttributeFileExtension(); @@ -48,58 +48,42 @@ public function testInstantiation() self::assertInstanceOf(ExtensionInterface::class, $extension); } - /** - * Test that the services are loaded. - * - * @return void - */ - public function testFactoryIsRegistered() + public function testFactoryIsRegistered(): void { - $container = $this->getMockBuilder(ContainerBuilder::class)->getMock(); + $container = new ContainerBuilder(); + $container->setParameter('kernel.debug', false); + $container->setParameter('metamodels.cache_dir', 'cache/dir'); + $container->setParameter('kernel.bundles', [MetaModelsContaoFrontendEditingBundle::class]); - $container - ->expects(self::atLeastOnce()) - ->method('setDefinition') - ->withConsecutive( - [ - 'metamodels.attribute_file.factory', - self::callback( - function ($value) { - /** @var Definition $value */ - $this->assertInstanceOf(Definition::class, $value); - $this->assertEquals(AttributeTypeFactory::class, $value->getClass()); - $this->assertCount(1, $value->getTag('metamodels.attribute_factory')); + $extension = new MetaModelsAttributeFileExtension(); + $extension->load([], $container); - return true; - } - ) - ] - ); - $container - ->method('getParameter') - ->willReturn(false, 'cache/dir', [MetaModelsContaoFrontendEditingBundle::class]); + self::assertTrue($container->hasAlias('metamodels.attribute_file.toolbox.file')); - $definition = $this->createMock(Definition::class); + self::assertTrue($container->hasDefinition('metamodels.attribute_file.event_listener.build_attribute')); + $definition = $container->getDefinition('metamodels.attribute_file.event_listener.build_attribute'); + self::assertCount(1, $definition->getTag('kernel.event_listener')); - $definition - ->method('setArgument') - ->willReturnCallback( - function (string $key, bool $value) { - switch ($key) { - case '$frontendEditing': - self::assertTrue($value); - break; - default: - } - } - ); + self::assertTrue($container->hasDefinition('metamodels.attribute_file.event_listener.image_size_options')); - $container - ->method('getDefinition') - ->willReturn($definition); + self::assertTrue($container->hasDefinition('metamodels.attribute_file.event_listener.build-data-definition')); + $definition = $container->getDefinition('metamodels.attribute_file.event_listener.build-data-definition'); + self::assertCount(1, $definition->getTag('kernel.event_listener')); - $extension = new MetaModelsAttributeFileExtension(); - $extension->load([], $container); + self::assertTrue($container->hasDefinition(DoctrineSchemaGenerator::class)); + $definition = $container->getDefinition(DoctrineSchemaGenerator::class); + self::assertCount(1, $definition->getTag('metamodels.schema-generator.doctrine')); + + self::assertTrue($container->hasParameter('metamodels.managed-schema-type-names')); + self::assertSame(['file'], $container->getParameter('metamodels.managed-schema-type-names')); + self::assertTrue($container->hasParameter('metamodels.attribute_file.cache_dir')); + self::assertSame( + '%metamodels.cache_dir%/attribute_file', + $container->getParameter('metamodels.attribute_file.cache_dir') + ); + self::assertTrue($container->hasDefinition(FileWidgetModeOptions::class)); + $definition = $container->getDefinition(FileWidgetModeOptions::class); + self::assertTrue($definition->getArgument('$frontendEditing')); } } diff --git a/tests/DeprecatedAutoloaderTest.php b/tests/DeprecatedAutoloaderTest.php index d164e59..c2302fb 100644 --- a/tests/DeprecatedAutoloaderTest.php +++ b/tests/DeprecatedAutoloaderTest.php @@ -25,7 +25,7 @@ use MetaModels\AttributeFileBundle\Attribute\AttributeTypeFactory; use MetaModels\AttributeFileBundle\Attribute\FileOrder; use MetaModels\AttributeFileBundle\DcGeneral\AttributeFileDefinition; -use MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsListener; +use MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsProvider; use PHPUnit\Framework\TestCase; /** @@ -35,7 +35,7 @@ * @covers \MetaModels\AttributeFileBundle\Attribute\FileOrder * @covers \MetaModels\AttributeFileBundle\Attribute\AttributeTypeFactory * @covers \MetaModels\AttributeFileBundle\DcGeneral\AttributeFileDefinition - * @covers \MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsListener + * @covers \MetaModels\AttributeFileBundle\EventListener\ImageSizeOptionsProvider */ class DeprecatedAutoloaderTest extends TestCase { @@ -49,7 +49,7 @@ class DeprecatedAutoloaderTest extends TestCase 'MetaModels\Attribute\File\FileOrder' => FileOrder::class, 'MetaModels\Attribute\File\AttributeTypeFactory' => AttributeTypeFactory::class, 'MetaModels\DcGeneral\AttributeFileDefinition' => AttributeFileDefinition::class, - 'MetaModels\Events\Attribute\File\ImageSizeOptions' => ImageSizeOptionsListener::class, + 'MetaModels\Events\Attribute\File\ImageSizeOptions' => ImageSizeOptionsProvider::class, ]; /** diff --git a/tests/EventListener/DcGeneral/Table/FilterSetting/RemoveAttIdOptionsTest.php b/tests/EventListener/DcGeneral/Table/FilterSetting/RemoveAttIdOptionsTest.php index e56a4b9..0d165d4 100644 --- a/tests/EventListener/DcGeneral/Table/FilterSetting/RemoveAttIdOptionsTest.php +++ b/tests/EventListener/DcGeneral/Table/FilterSetting/RemoveAttIdOptionsTest.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/attribute_file. * - * (c) 2012-2021 The MetaModels team. + * (c) 2012-2023 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,7 +12,8 @@ * * @package MetaModels/attribute_file * @author Sven Baumann - * @copyright 2012-2021 The MetaModels team. + * @author Ingolf Steinhardt + * @copyright 2012-2023 The MetaModels team. * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -85,9 +86,19 @@ public function dataProviderTestRemoveOption() return [ [['foo' => 'bar [file]', 'filesort' => 'foo'], 'foo', 'foo', ['foo' => 'bar [file]', 'filesort' => 'foo']], - [['foo' => 'bar [file]', 'filesort' => 'foo'], 'foo', 'attr_id', ['foo' => 'bar [file]', 'filesort' => 'foo']], + [ + ['foo' => 'bar [file]', 'filesort' => 'foo'], + 'foo', + 'attr_id', + ['foo' => 'bar [file]', 'filesort' => 'foo'] + ], [['foo' => 'bar [file]'], 'tl_metamodel_filtersetting', 'attr_id', ['foo' => 'bar [file]']], - [['foo' => 'bar [file]'], 'tl_metamodel_filtersetting', 'attr_id', ['foo' => 'bar [file]', 'foo__sort' => 'foo']] + [ + ['foo' => 'bar [file]'], + 'tl_metamodel_filtersetting', + 'attr_id', + ['foo' => 'bar [file]', 'foo__sort' => 'foo'] + ] ]; } diff --git a/tests/EventListener/Factory/AddAttributeInformationTest.php b/tests/EventListener/Factory/AddAttributeInformationTest.php index 164bf6b..ad0f233 100644 --- a/tests/EventListener/Factory/AddAttributeInformationTest.php +++ b/tests/EventListener/Factory/AddAttributeInformationTest.php @@ -3,7 +3,7 @@ /** * This file is part of MetaModels/core. * - * (c) 2012-2021 The MetaModels team. + * (c) 2012-2023 The MetaModels team. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,7 +12,8 @@ * * @package MetaModels/core * @author Sven Baumann - * @copyright 2012-2021 The MetaModels team. + * @author Ingolf Steinhardt + * @copyright 2012-2023 The MetaModels team. * @license https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -32,6 +33,7 @@ */ class AddAttributeInformationTest extends TestCase { + /** @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function dataProviderAddInformation() { return [ diff --git a/tests/Schema/DoctrineSchemaGeneratorTest.php b/tests/Schema/DoctrineSchemaGeneratorTest.php new file mode 100644 index 0000000..b0786bd --- /dev/null +++ b/tests/Schema/DoctrineSchemaGeneratorTest.php @@ -0,0 +1,92 @@ + + * @author Ingolf Steinhardt + * @copyright 2012-2024 The MetaModels team. + * @license https://github.com/MetaModels/attribute_file/blob/master/LICENSE LGPL-3.0-or-later + * @filesource + */ + +declare(strict_types=1); + +namespace MetaModels\AttributeFileBundle\Test\Schema; + +use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; +use MetaModels\AttributeFileBundle\Schema\DoctrineSchemaGenerator; +use MetaModels\Information\AttributeInformation; +use PHPUnit\Framework\TestCase; + +/** + * This tests the schema generator. + * + * @covers \MetaModels\AttributeFileBundle\Schema\DoctrineSchemaGenerator + */ +class DoctrineSchemaGeneratorTest extends TestCase +{ + /** + * Test the generate method. + * + * @return void + */ + public function testGenerate(): void + { + $instance = new DoctrineSchemaGenerator(); + $reflection = new \ReflectionMethod(DoctrineSchemaGenerator::class, 'generateAttribute'); + $reflection->setAccessible(true); + + $tableSchema = new Table('mm_test'); + $attribute = new AttributeInformation('test', 'file', ['file_multiple' => false]); + + $reflection->invoke($instance, $tableSchema, $attribute); + + $this->assertTrue($tableSchema->hasColumn('test')); + $column = $tableSchema->getColumn('test'); + $this->assertSame('test', $column->getName()); + $this->assertSame(Type::getType(Types::BLOB), $column->getType()); + $this->assertSame(false, $column->getNotnull()); + + $this->assertFalse($tableSchema->hasColumn('test__sort')); + } + + /** + * Test the generate method. + * + * @return void + */ + public function testGenerateForMultiple(): void + { + $instance = new DoctrineSchemaGenerator(); + $reflection = new \ReflectionMethod(DoctrineSchemaGenerator::class, 'generateAttribute'); + $reflection->setAccessible(true); + + $tableSchema = new Table('mm_test'); + $attribute = new AttributeInformation('test', 'file', ['file_multiple' => true]); + + $reflection->invoke($instance, $tableSchema, $attribute); + + $this->assertTrue($tableSchema->hasColumn('test')); + $column = $tableSchema->getColumn('test'); + $this->assertSame('test', $column->getName()); + $this->assertSame(Type::getType(Types::BLOB), $column->getType()); + $this->assertSame(false, $column->getNotnull()); + + $this->assertTrue($tableSchema->hasColumn('test__sort')); + $column = $tableSchema->getColumn('test__sort'); + $this->assertSame('test__sort', $column->getName()); + $this->assertSame(Type::getType(Types::BLOB), $column->getType()); + $this->assertSame(false, $column->getNotnull()); + } +}