From c1197c9518e41ff0153979f80e471ca03897ed8e Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Mon, 28 Feb 2022 10:50:41 +0100 Subject: [PATCH 01/17] Install phpcq-2 and update dependencies --- .composer-require-checker.json | 2 + .gitattributes | 8 +-- .github/workflows/diagnostics.yml | 77 ++++++++++++++++++++ .gitignore | 5 +- .phpcq.lock | 1 + .phpcq.yaml.dist | 114 ++++++++++++++++++++++++++++++ .phpmd.xml | 37 ++++++++++ .travis.yml | 45 ------------ README.md | 1 + build.xml | 20 ------ composer.json | 18 ++--- phpunit.xml.dist | 25 ++++--- psalm.xml | 13 ++++ 13 files changed, 277 insertions(+), 89 deletions(-) create mode 100644 .composer-require-checker.json create mode 100644 .github/workflows/diagnostics.yml create mode 100644 .phpcq.lock create mode 100644 .phpcq.yaml.dist create mode 100644 .phpmd.xml delete mode 100644 .travis.yml delete mode 100644 build.xml create mode 100644 psalm.xml diff --git a/.composer-require-checker.json b/.composer-require-checker.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/.composer-require-checker.json @@ -0,0 +1,2 @@ +{ +} diff --git a/.gitattributes b/.gitattributes index 547ebf9..517b65f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,9 +1,9 @@ -.check-author.yml export-ignore .gitattributes export-ignore .github export-ignore .gitignore export-ignore -.travis.yml export-ignore -build.default.properties export-ignore -build.xml export-ignore +.phpcq.* export-ignore +.phpmd.xml +.phpunit.result.cache phpunit.xml.dist export-ignore +psalm.xml export-ignore /tests export-ignore diff --git a/.github/workflows/diagnostics.yml b/.github/workflows/diagnostics.yml new file mode 100644 index 0000000..1da228f --- /dev/null +++ b/.github/workflows/diagnostics.yml @@ -0,0 +1,77 @@ +name: cyberspectrum/i18n + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - php: '7.4' + output: '-o github-action -o default' + phpcq_install: 'install' + composer_install: 'update --prefer-lowest' + - php: '7.4' + output: '-o github-action -o default' + phpcq_install: 'update' + composer_install: 'update' + - php: '8.0' + output: '-o github-action -o default' + phpcq_install: 'update' + composer_install: 'update' + - php: '8.1' + output: '-o github-action -o default' + phpcq_install: 'update' + composer_install: 'update' + + steps: + - name: PHP ${{ matrix.php }} Pull source + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + # see https://github.com/shivammathur/setup-php + - name: PHP ${{ matrix.php }} Setup PHP. + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + + - name: PHP ${{ matrix.php }} Cache composer cache directory + uses: actions/cache@v1 + env: + cache-name: composer-cache-dir-${{ matrix.php }} + with: + path: ~/.cache/composer + key: ${{ runner.os }}-build-${{ env.cache-name }} + + - name: PHP ${{ matrix.php }} Cache vendor directory + uses: actions/cache@v1 + env: + cache-name: composer-vendor-${{ matrix.php }} + with: + path: vendor + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + + - name: PHP ${{ matrix.php }} Install composer dependencies + run: composer ${{ matrix.composer_install }} --prefer-stable --no-interaction --no-progress + + - name: PHP ${{ matrix.php }} Update phpcq + run: ./vendor/bin/phpcq self-update + + - name: PHP ${{ matrix.php }} Install phpcq toolchain + run: ./vendor/bin/phpcq ${{ matrix.phpcq_install }} -v + + - name: PHP ${{ matrix.php }} Run tests + run: ./vendor/bin/phpcq run -v ${{ matrix.output }} + + - name: PHP ${{ matrix.php }} Upload build directory to artifact + uses: actions/upload-artifact@v2 + if: ${{ success() }} || ${{ failure() }} + with: + name: phpcq-builds-php-${{ matrix.php }} + path: .phpcq/build/ diff --git a/.gitignore b/.gitignore index f4974e1..38e2637 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ vendor/ composer.lock -build/ -build.properties -phpunix.xml +.phpcq +phpunit.xml .phpunit.result.cache diff --git a/.phpcq.lock b/.phpcq.lock new file mode 100644 index 0000000..2f42a09 --- /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/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.5.16","url":"https://phar.phpunit.de/phpunit-9.5.16.phar","requirements":{"php":{"php":">=7.3","ext-dom":"*","ext-json":"*","ext-libxml":"*","ext-mbstring":"*","ext-xml":"*","ext-xmlwriter":"*"}},"checksum":{"type":"sha-256","value":"342166d3067cb86a4d9620d0a49b9ae4b4bbe25d5d751a0ecfd3ed4e96409b0a"},"signature":"https://phar.phpunit.de/phpunit-9.5.16.phar.asc"}}},"psalm":{"api-version":"1.0.0","version":"1.0.1.0","type":"php-file","url":"https://phpcq.github.io/repository/psalm-1.0.1.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"psalm":"^3.0 || ^4.0"}},"checksum":{"type":"sha-512","value":"fb591fbea784d65ea1b63ba597616c2dd6346958a61a9129aacf612e0deaa14c0de33d9a37cf81b5ed717f09cc3f1280149a0d46576fc838241070176710675f"},"tools":{"psalm":{"version":"4.22.0","url":"https://github.com/vimeo/psalm/releases/download/4.22.0/psalm.phar","requirements":{"php":{"php":"^7.1|^8","ext-SimpleXML":"*","ext-ctype":"*","ext-dom":"*","ext-json":"*","ext-libxml":"*","ext-mbstring":"*","ext-tokenizer":"*"}},"checksum":null,"signature":"https://github.com/vimeo/psalm/releases/download/4.22.0/psalm.phar.asc"}}},"composer-require-checker":{"api-version":"1.0.0","version":"1.0.1.0","type":"php-file","url":"https://phpcq.github.io/repository/composer-require-checker-1.0.1.0.php","signature":null,"requirements":{"php":{"php":"^7.4 || ^8.0"},"tool":{"composer-require-checker":"^3.8"}},"checksum":{"type":"sha-512","value":"5b0fd8cd5e0f5761c53b9d5375b6f6ba50f148468896248f823cc2a48361adfd872556066764b1b544ff51ffd5de60d6f9a75050db00b257d807976ac761bc3a"},"tools":{"composer-require-checker":{"version":"3.8.0","url":"https://github.com/maglnet/ComposerRequireChecker/releases/download/3.8.0/composer-require-checker.phar","requirements":{"php":{"php":"^7.4 || ^8.0","ext-json":"*","ext-phar":"*"}},"checksum":null,"signature":"https://github.com/maglnet/ComposerRequireChecker/releases/download/3.8.0/composer-require-checker.phar.asc"}}},"phpmd":{"api-version":"1.0.0","version":"1.0.1.0","type":"php-file","url":"https://phpcq.github.io/repository/phpmd-1.0.1.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"phpmd":"^2.6.1"}},"checksum":{"type":"sha-512","value":"88e267b9c36b2edc85e924717606b626e005ac8d97b1f65f5331e2a3b3894dec2cf124f6187541bf759d026477b6d94daacc5d5c81bb09714a68ffabe5698dc5"},"tools":{"phpmd":{"version":"2.11.1","url":"https://github.com/phpmd/phpmd/releases/download/2.11.1/phpmd.phar","requirements":{"php":{"php":">=5.3.9","ext-xml":"*"}},"checksum":null,"signature":null}}},"phpcpd":{"api-version":"1.0.0","version":"1.1.1.0","type":"php-file","url":"https://phpcq.github.io/repository/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"}}},"phploc":{"api-version":"1.0.0","version":"1.0.0.0","type":"php-file","url":"https://phpcq.github.io/repository/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"}}},"phpcs":{"api-version":"1.0.0","version":"1.1.0.0","type":"php-file","url":"https://phpcq.github.io/repository/phpcs-1.1.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":"2737022369da1318cc4e0ea194e8a81019f7b079080d869aab878b7486052fdbe68fee3f28131f35573226def1aabd4bd005e038ee7b767c137b1107c1492a83"},"tools":{"phpcs":{"version":"3.6.2","url":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcs.phar","requirements":{"php":{"php":">=5.4.0","ext-tokenizer":"*","ext-xmlwriter":"*","ext-simplexml":"*"}},"checksum":null,"signature":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcs.phar.asc"},"phpcbf":{"version":"3.6.2","url":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcbf.phar","requirements":{"php":{"php":">=5.4.0","ext-tokenizer":"*","ext-xmlwriter":"*","ext-simplexml":"*"}},"checksum":null,"signature":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcbf.phar.asc"}}},"composer-normalize":{"api-version":"1.0.0","version":"1.1.0.0","type":"php-file","url":"https://phpcq.github.io/repository/composer-normalize-1.1.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-json":"*"},"tool":{"composer-normalize":"^2.1"}},"checksum":{"type":"sha-512","value":"d59d3557cb20630734878a9115df5dd32d5aff815e5b15be36f6fb5d6e9d83dd36efd84215ab6529edcc924f600946f739a0d9e67723deff95c88346ab502498"},"tools":{"composer-normalize":{"version":"2.23.1","url":"https://github.com/ergebnis/composer-normalize/releases/download/2.23.1/composer-normalize.phar","requirements":{"php":{"php":"^7.4 || ^8.0"}},"checksum":null,"signature":"https://github.com/ergebnis/composer-normalize/releases/download/2.23.1/composer-normalize.phar.asc"}}}},"tools":[]} \ No newline at end of file diff --git a/.phpcq.yaml.dist b/.phpcq.yaml.dist new file mode 100644 index 0000000..f9f93bf --- /dev/null +++ b/.phpcq.yaml.dist @@ -0,0 +1,114 @@ +phpcq: + repositories: + - https://phpcq.github.io/repository/repository.json + directories: + - src + - tests + artifact: .phpcq/build + + plugins: + phpunit: + version: ^1.0 + signed: false + psalm: + version: ^1.0 + signed: false + composer-require-checker: + version: ^1.0 + signed: false + requirements: + composer-require-checker: + signed: false + version: ^3.3 + phpmd: + version: ^1.0 + signed: false + requirements: + phpmd: + signed: false + phpcpd: + version: ^1.0 + signed: false + requirements: + phpcpd: + version: ^6.0 + phploc: + version: ^1.0 + signed: false + phpcs: + version: ^1.0 + signed: false + composer-normalize: + version: ^1.0 + signed: false + trusted-keys: + # sb@sebastian-bergmann.de + - 4AA394086372C20A + # psalm + - 8A03EA3B385DBAA1 + - 12CE0F1D262429A5 + # magl@magll.net + - D2CCAC42F6295E7D + # PHP_CodeSniffer + - 31C7E470E2138192 + # Composer normalize + - C00543248C87FB13 + # phpmd + - 0F9684B8B16B7AB0 + # composer-require-checker + - 033E5F8D801A2F8D + +tasks: + fix: + - composer-normalize-fix + - phpcbf + verify: + - composer-require-checker + - composer-normalize + analyze: + - phploc + - phpcpd + - phpmd + - phpcs + - psalm + - phpunit + default: + - composer-require-checker + - composer-normalize + - phploc + # currently breaks due to incompatible plugin. :/ + #- phpcpd + - phpmd + - phpcs + - psalm + - phpunit + phpcpd: + plugin: phpcpd + + phpmd: + plugin: phpmd + config: + ruleset: + - ./.phpmd.xml + + composer-normalize-fix: + plugin: composer-normalize + config: + dry_run: false + + composer-require-checker: + plugin: composer-require-checker + config: + config_file: '.composer-require-checker.json' + + phpcs: + plugin: phpcs + config: &phpcs-config + standard: PSR12 + custom_flags: + - '--extensions=php' + + phpcbf: + plugin: phpcs + config: + <<: *phpcs-config 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/.travis.yml b/.travis.yml deleted file mode 100644 index 09078ac..0000000 --- a/.travis.yml +++ /dev/null @@ -1,45 +0,0 @@ -dist: xenial - -addons: - apt: - packages: - - ant-optional - -language: php - -php: - - '7.4' - - '7.3' - - '7.2' - -env: - - SYMFONY_VERSION='^5.0' - - SYMFONY_VERSION='^4.0' - - SYMFONY_VERSION='^3.0' - -sudo: false - -before_script: - - echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - - travis_retry composer self-update && composer --version - - travis_retry composer require symfony/finder ${SYMFONY_VERSION} --no-update - - travis_retry composer require symfony/filesystem ${SYMFONY_VERSION} --no-update - - > - if [ "x${TRAVIS_TAG}" != "x" ]; then - COMPOSER_ROOT_VERSION=${TRAVIS_TAG} travis_retry composer update --prefer-dist --no-interaction; - else - COMPOSER_ROOT_VERSION=$([[ ${TRAVIS_BRANCH} =~ hotfix/([0-9.]*(-(alpha|beta|rc)[0-9]+)?) ]] \ - && echo ${BASH_REMATCH[1]} \ - || echo dev-${TRAVIS_BRANCH}) \ - travis_retry composer update --prefer-dist --no-interaction; - fi - -script: ant -keep-going - -# Hack to make things work again - we can not use a shallow repository. -git: - depth: 2147483647 - -cache: - directories: - - vendor diff --git a/README.md b/README.md index 9b19e28..4bb7993 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # i18n-xliff library +[![Code Quality Diagnostics](https://github.com/cyberspectrum/i18n-xliff/actions/workflows/diagnostics.yml/badge.svg)](https://github.com/cyberspectrum/i18n-xliff/actions/workflows/diagnostics.yml) [![Build Status](https://travis-ci.org/cyberspectrum/i18n-xliff.png)](https://travis-ci.org/cyberspectrum/i18n-xliff) [![Latest Version tagged](http://img.shields.io/github/tag/cyberspectrum/i18n-xliff.svg)](https://github.com/cyberspectrum/i18n-xliff/tags) [![Latest Version on Packagist](http://img.shields.io/packagist/v/cyberspectrum/i18n-xliff.svg)](https://packagist.org/packages/cyberspectrum/i18n-xliff) diff --git a/build.xml b/build.xml deleted file mode 100644 index a338eb9..0000000 --- a/build.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - diff --git a/composer.json b/composer.json index d2cc3a5..353595f 100644 --- a/composer.json +++ b/composer.json @@ -2,11 +2,10 @@ "name": "cyberspectrum/i18n-xliff", "description": "Simple translation mapping and exporting of xliff files", "license": "MIT", + "type": "library", "keywords": [ "i18n" ], - "type": "library", - "homepage": "https://www.cyberspectrum.de/", "authors": [ { "name": "Christian Schiffler", @@ -15,21 +14,22 @@ "role": "Maintainer" } ], + "homepage": "https://www.cyberspectrum.de/", "support": { "email": "info@cyberspectrum.de", "issues": "https://github.com/cyberspectrum/i18n-xliff/issues", "source": "https://github.com/cyberspectrum/i18n-xliff" }, "require": { - "php": "^7.1.3", - "cyberspectrum/i18n": "^1.0.0@dev", - "psr/log": "^1.1", - "symfony/finder": "^3.4 | ^4.2 | ^5.0", - "webmozart/path-util": "^2.3" + "php": "^7.4 || ^8.0", + "ext-dom": "*", + "cyberspectrum/i18n": "dev-fix/phpcq-2 as 1.0.0@dev", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "symfony/finder": "^3.4 || ^4.2 || ^5.0 || ^6.0" }, "require-dev": { - "phpcq/all-tasks": "^1.3", - "symfony/filesystem": "^3.4 | ^4.2 | ^5.0" + "phpcq/runner-bootstrap": "^1.0@dev", + "symfony/filesystem": "^3.4 || ^4.2 || ^5.0 || ^6.0" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e6af62e..323d334 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,17 +1,26 @@ - + + + - ./tests/ + tests - - - ./src/ - - + + + ./src + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..2569cf7 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,13 @@ + + + + + + From d73db2d7a93bf823ecdc94e575c641ddf2171ae3 Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Mon, 28 Feb 2022 16:00:19 +0100 Subject: [PATCH 02/17] Fix issues --- .github/workflows/diagnostics.yml | 4 + build.default.properties | 34 --- composer.json | 6 +- src/Exception/LanguageMismatchException.php | 75 ++----- src/WritableXliffDictionary.php | 97 ++++----- src/WritableXliffTranslationValue.php | 78 +++---- src/XliffDictionary.php | 58 +---- src/XliffDictionaryDefinitionBuilder.php | 45 ++-- src/XliffDictionaryProvider.php | 109 +++++----- src/XliffTranslationValue.php | 66 +----- src/Xml/XliffFile.php | 198 ++++++++---------- src/Xml/XmlElement.php | 66 +++--- tests/TestCase.php | 27 +-- tests/WritableXliffDictionaryTest.php | 125 +++-------- tests/WritableXliffTranslationValueTest.php | 94 +++------ .../XliffDictionaryDefinitionBuilderTest.php | 34 +-- tests/XliffDictionaryProviderTest.php | 76 ++----- tests/XliffDictionaryTest.php | 61 ++---- tests/XliffTranslationValueTest.php | 57 ++--- tests/Xml/XliffFileTest.php | 110 +++------- 20 files changed, 436 insertions(+), 984 deletions(-) delete mode 100644 build.default.properties diff --git a/.github/workflows/diagnostics.yml b/.github/workflows/diagnostics.yml index 1da228f..cd50c20 100644 --- a/.github/workflows/diagnostics.yml +++ b/.github/workflows/diagnostics.yml @@ -7,7 +7,11 @@ on: jobs: build: runs-on: ubuntu-latest + + name: PHP ${{ matrix.php }} + strategy: + fail-fast: false matrix: include: - php: '7.4' diff --git a/build.default.properties b/build.default.properties deleted file mode 100644 index bb2b643..0000000 --- a/build.default.properties +++ /dev/null @@ -1,34 +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 -phpcs.customflags=--report=checkstyle --report-file=${basedir}/build/logs/checkstyle.xml - -pdepend.output=\ - --jdepend-xml=${basedir}/build/logs/jdepend.xml \ - --jdepend-chart=${basedir}/build/pdepend/dependencies.svg \ - --overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg - -phpcpd.customflags=--log-pmd ${basedir}/build/logs/pmd-cpd.xml - -phploc.output=\ - --log-csv=${basedir}/build/logs/phploc.csv \ - --log-xml=${basedir}/build/logs/phploc.xml - -phpmd.ruleset=${basedir}/vendor/phpcq/coding-standard/phpmd/ruleset.xml -phpmd.excluded= -phpmd.format=xml -phpmd.customflags=--reportfile ${basedir}/build/logs/pmd.xml - -pdepend.excluded= - -phpunit.customflags=\ - --coverage-html build/coverage/ \ - --coverage-clover build/logs/clover.xml \ - --coverage-crap4j build/logs/crap4j.xml \ - --coverage-text --colors=never \ - --log-junit build/logs/junit.xml diff --git a/composer.json b/composer.json index 353595f..af252ef 100644 --- a/composer.json +++ b/composer.json @@ -24,12 +24,12 @@ "php": "^7.4 || ^8.0", "ext-dom": "*", "cyberspectrum/i18n": "dev-fix/phpcq-2 as 1.0.0@dev", - "psr/log": "^1.1 || ^2.0 || ^3.0", + "psr/log": "^1.1.4 || ^2.0 || ^3.0", + "symfony/filesystem": "^3.4 || ^4.2 || ^5.0 || ^6.0", "symfony/finder": "^3.4 || ^4.2 || ^5.0 || ^6.0" }, "require-dev": { - "phpcq/runner-bootstrap": "^1.0@dev", - "symfony/filesystem": "^3.4 || ^4.2 || ^5.0 || ^6.0" + "phpcq/runner-bootstrap": "^1.0@dev" }, "autoload": { "psr-4": { diff --git a/src/Exception/LanguageMismatchException.php b/src/Exception/LanguageMismatchException.php index 6070dde..1ba3102 100644 --- a/src/Exception/LanguageMismatchException.php +++ b/src/Exception/LanguageMismatchException.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Exception; @@ -26,33 +9,17 @@ */ class LanguageMismatchException extends \RuntimeException { - /** - * The expected source. - * - * @var string - */ - private $expectedSource; + /** The expected source. */ + private string $expectedSource; - /** - * The expected target. - * - * @var string - */ - private $expectedTarget; + /** The expected target. */ + private string $expectedTarget; - /** - * The real source. - * - * @var string - */ - private $realSource; + /** The real source. */ + private string $realSource; - /** - * The real target. - * - * @var string - */ - private $realTarget; + /** The real target. */ + private string $realTarget; /** * Create a new instance. @@ -77,41 +44,25 @@ public function __construct(string $expectedSource, string $expectedTarget, stri )); } - /** - * Retrieve expectedSource. - * - * @return string - */ + /** Retrieve expected source. */ public function getExpectedSource(): string { return $this->expectedSource; } - /** - * Retrieve expectedTarget. - * - * @return mixed - */ + /** Retrieve expected target. */ public function getExpectedTarget(): string { return $this->expectedTarget; } - /** - * Retrieve realSource. - * - * @return mixed - */ + /** Retrieve real source. */ public function getRealSource(): string { return $this->realSource; } - /** - * Retrieve realTarget. - * - * @return mixed - */ + /** Retrieve real target. */ public function getRealTarget(): string { return $this->realTarget; diff --git a/src/WritableXliffDictionary.php b/src/WritableXliffDictionary.php index 650a150..f0eaa55 100644 --- a/src/WritableXliffDictionary.php +++ b/src/WritableXliffDictionary.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff; @@ -27,6 +10,14 @@ use CyberSpectrum\I18N\Exception\TranslationAlreadyContainedException; use CyberSpectrum\I18N\Exception\TranslationNotFoundException; use CyberSpectrum\I18N\TranslationValue\WritableTranslationValueInterface; +use CyberSpectrum\I18N\Xliff\Xml\XmlElement; +use DateTime; +use LogicException; +use RuntimeException; + +use function dirname; +use function file_exists; +use function is_writable; /** * This represents a dictionary that can read and write xliff files. @@ -35,36 +26,35 @@ class WritableXliffDictionary extends XliffDictionary implements WritableDictionaryInterface, BufferedWritableDictionaryInterface { - /** - * Flag if the contents have been changed. - * - * @var bool - */ - private $changed = false; + /** The filename to work on. */ + private string $filename; - /** - * Flag if the dictionary is already buffering. - * - * @var bool - */ - private $buffering = false; + /** Flag if the contents have been changed. */ + private bool $changed = false; + + /** Flag if the dictionary is already buffering. */ + private bool $buffering = false; /** * Create a new instance. * - * @param string $filename The filename to use or null when none should be loaded. - * @param string $sourceLanguage The source language. - * @param string $targetLanguage The destination language. + * @param string $filename The filename to use or null when none should be loaded. + * @param string|null $sourceLanguage The source language. + * @param string|null $targetLanguage The destination language. * * @throws NotSupportedException When the file is not writable. */ - public function __construct($filename, string $sourceLanguage = null, string $targetLanguage = null) + public function __construct(string $filename, ?string $sourceLanguage = null, ?string $targetLanguage = null) { - if (!is_writable($filename) && !(!file_exists($filename) && is_writable(\dirname($filename)))) { + if (!is_writable($filename) && !(!file_exists($filename) && is_writable(dirname($filename)))) { throw new NotSupportedException($this, 'File is not writable: ' . $filename); } parent::__construct($filename); + $this->filename = $filename; + if ($this->filename && is_readable($this->filename)) { + $this->xliff->load($this->filename); + } if (!file_exists($filename)) { if ($sourceLanguage) { @@ -93,27 +83,22 @@ public function add(string $key): WritableTranslationValueInterface return new WritableXliffTranslationValue($this, $this->xliff->createTranslationUnit($key)); } - /** - * {@inheritDoc} - * - * @throws TranslationNotFoundException When the translation unit can not be found. - */ public function remove(string $key): void { if (null === $unit = $this->xliff->searchTranslationUnit($key)) { throw new TranslationNotFoundException($key, $this); } - $unit->parentNode->removeChild($unit); + $parent = $unit->parentNode; + if (!$parent instanceof XmlElement) { + throw new LogicException('Unparented node encountered.'); + } + + $parent->removeChild($unit); $this->markChanged(); } - /** - * {@inheritDoc} - * - * @throws TranslationNotFoundException When the translation unit can not be found. - */ - public function getWritable($key): WritableTranslationValueInterface + public function getWritable(string $key): WritableTranslationValueInterface { if (null === $unit = $this->xliff->searchTranslationUnit($key)) { throw new TranslationNotFoundException($key, $this); @@ -125,24 +110,24 @@ public function getWritable($key): WritableTranslationValueInterface /** * {@inheritDoc} * - * @throws \RuntimeException When already buffering. + * @throws RuntimeException When already buffering. */ public function beginBuffering(): void { if ($this->buffering) { - throw new \RuntimeException('Already buffering.'); + throw new RuntimeException('Already buffering.'); } } /** * {@inheritDoc} * - * @throws \RuntimeException When the dictionary is not currently buffering. + * @throws RuntimeException When the dictionary is not currently buffering. */ public function commitBuffer(): void { if (!$this->buffering) { - throw new \RuntimeException('Not buffering.'); + throw new RuntimeException('Not buffering.'); } $this->buffering = false; if ($this->changed) { @@ -162,14 +147,12 @@ public function isBuffering(): bool /** * Mark the file as changed. * - * @return void - * * @internal Should only be called from Xliff dictionary classes. */ public function markChanged(): void { $this->changed = true; - $this->xliff->setDate(new \DateTime()); + $this->xliff->setDate(new DateTime()); if (!$this->buffering) { $this->xliff->save($this->filename); } @@ -179,8 +162,6 @@ public function markChanged(): void * Set the source language. * * @param string $language The language. - * - * @return void */ public function setSourceLanguage(string $language): void { @@ -192,8 +173,6 @@ public function setSourceLanguage(string $language): void * Set the source language. * * @param string $language The language. - * - * @return void */ public function setTargetLanguage(string $language): void { @@ -205,8 +184,6 @@ public function setTargetLanguage(string $language): void * Set the original. * * @param string $source The original. - * - * @return void */ public function setOriginal(string $source): void { diff --git a/src/WritableXliffTranslationValue.php b/src/WritableXliffTranslationValue.php index 94e6211..3dbccd6 100644 --- a/src/WritableXliffTranslationValue.php +++ b/src/WritableXliffTranslationValue.php @@ -1,29 +1,14 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff; use CyberSpectrum\I18N\TranslationValue\WritableTranslationValueInterface; use CyberSpectrum\I18N\Xliff\Xml\XliffFile; use CyberSpectrum\I18N\Xliff\Xml\XmlElement; +use DOMDocument; +use LogicException; /** * This provides access to a xliff translation value. @@ -38,84 +23,75 @@ class WritableXliffTranslationValue extends XliffTranslationValue implements Wri * @param WritableXliffDictionary $dictionary The dictionary. * @param XmlElement $node The XML node. */ - // @codingStandardsIgnoreStart This is no useless constructor overriding, we change the parameter type. public function __construct(WritableXliffDictionary $dictionary, XmlElement $node) { parent::__construct($dictionary, $node); } - // @codingStandardsIgnoreEnd - /** - * {@inheritDoc} - */ - public function setSource(string $value) + public function setSource(string $value): void { if (null === ($element = $this->getSourceElement())) { $element = $this->node->appendChild( - $this->node->ownerDocument->createElementNS(XliffFile::XLIFF_NS, 'source') + $this->getDocument()->createElementNS(XliffFile::XLIFF_NS, 'source') ); } + $parent = $element->parentNode; + if (!$parent instanceof XmlElement) { + throw new LogicException('Unparented node encountered.'); + } if (null === $textNode = $element->firstChild) { - $element->appendChild($this->node->ownerDocument->createTextNode($value)); - $element->parentNode->setAttributeNS(XliffFile::XLIFF_NS, 'state', 'new'); + $element->appendChild($this->getDocument()->createTextNode($value)); + $parent->setAttributeNS(XliffFile::XLIFF_NS, 'state', 'new'); $this->dictionary->markChanged(); - return $this; + return; } $textNode->nodeValue = $value; - $element->parentNode->setAttributeNS(XliffFile::XLIFF_NS, 'state', 'needs-translation'); + $parent->setAttributeNS(XliffFile::XLIFF_NS, 'state', 'needs-translation'); $this->dictionary->markChanged(); - - return $this; } - /** - * {@inheritDoc} - */ - public function setTarget(string $value) + public function setTarget(string $value): void { if (null === ($element = $this->getTargetElement())) { $element = $this->node->appendChild( - $this->node->ownerDocument->createElementNS(XliffFile::XLIFF_NS, 'target') + $this->getDocument()->createElementNS(XliffFile::XLIFF_NS, 'target') ); } if (null === $textNode = $element->firstChild) { - $element->appendChild($this->node->ownerDocument->createTextNode($value)); + $element->appendChild($this->getDocument()->createTextNode($value)); $this->dictionary->markChanged(); - return $this; + return; } $textNode->nodeValue = $value; $this->dictionary->markChanged(); - - return $this; } - /** - * {@inheritDoc} - */ - public function clearSource() + public function clearSource(): void { if (($element = $this->getSourceElement()) && $element->firstChild) { $element->removeChild($element->firstChild); } - - return $this; } - /** - * {@inheritDoc} - */ - public function clearTarget() + public function clearTarget(): void { if (($element = $this->getTargetElement()) && $element->firstChild) { $element->removeChild($element->firstChild); } + } - return $this; + private function getDocument(): DOMDocument + { + $document = $this->node->ownerDocument; + if (!$document instanceof DOMDocument) { + throw new LogicException('Failed to obtain owner document'); + } + return $document; } } diff --git a/src/XliffDictionary.php b/src/XliffDictionary.php index a3624de..8953548 100644 --- a/src/XliffDictionary.php +++ b/src/XliffDictionary.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff; @@ -25,44 +8,32 @@ use CyberSpectrum\I18N\Exception\TranslationNotFoundException; use CyberSpectrum\I18N\TranslationValue\TranslationValueInterface; use CyberSpectrum\I18N\Xliff\Xml\XliffFile; +use Traversable; + +use function is_readable; /** * This represents a dictionary that can read and write xliff files. */ class XliffDictionary implements DictionaryInterface { - /** - * The filename to work on. - * - * @var string|null - */ - protected $filename; - - /** - * The XLIFF document. - * - * @var XliffFile - */ - protected $xliff; + /** The XLIFF document. */ + protected XliffFile $xliff; /** * Create a new instance. * * @param string|null $filename The filename to use or null when none should be loaded. */ - public function __construct($filename = null) + public function __construct(?string $filename = null) { $this->xliff = new XliffFile(); - $this->filename = $filename; - if ($this->filename && is_readable($this->filename)) { - $this->xliff->load($this->filename); + if ($filename && is_readable($filename)) { + $this->xliff->load($filename); } } - /** - * {@inheritDoc} - */ - public function keys(): \Traversable + public function keys(): Traversable { return $this->xliff->extractTranslationKeys(); } @@ -81,25 +52,16 @@ public function get(string $key): TranslationValueInterface return new XliffTranslationValue($this, $unit); } - /** - * {@inheritDoc} - */ public function has(string $key): bool { return null !== $this->xliff->searchTranslationUnit($key); } - /** - * {@inheritDoc} - */ public function getSourceLanguage(): string { return $this->xliff->getSourceLanguage(); } - /** - * {@inheritDoc} - */ public function getTargetLanguage(): string { return $this->xliff->getTargetLanguage(); diff --git a/src/XliffDictionaryDefinitionBuilder.php b/src/XliffDictionaryDefinitionBuilder.php index 02e384f..71c6b13 100644 --- a/src/XliffDictionaryDefinitionBuilder.php +++ b/src/XliffDictionaryDefinitionBuilder.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff; @@ -25,28 +8,38 @@ use CyberSpectrum\I18N\Configuration\Definition\Definition; use CyberSpectrum\I18N\Configuration\Definition\DictionaryDefinition; use CyberSpectrum\I18N\Configuration\DefinitionBuilder\DefinitionBuilderInterface; +use InvalidArgumentException; /** * Builds xliff dictionary definitions. + * + * @psalm-type TXliffDictionaryConfigurationArray=array{ + * name: string, + * } */ class XliffDictionaryDefinitionBuilder implements DefinitionBuilderInterface { /** - * Build a definition from the passed values. - * - * @param Configuration $configuration The configuration. - * @param array $data The configuration values. - * - * @return Definition|DictionaryDefinition - * - * @@SuppressWarnings(PHPMD.UnusedFormalParameter) + * {@inheritDoc} */ public function build(Configuration $configuration, array $data): Definition { + $this->checkConfiguration($data); $name = $data['name']; unset($data['name']); $data['type'] = 'xliff'; return new DictionaryDefinition($name, $data); } + + /** @psalm-assert TXliffDictionaryConfigurationArray $data */ + private function checkConfiguration(array $data): void + { + if (!array_key_exists('name', $data)) { + throw new InvalidArgumentException('Missing key \'name\''); + } + if (!is_string($data['name'])) { + throw new InvalidArgumentException('\'name\' must be a string'); + } + } } diff --git a/src/XliffDictionaryProvider.php b/src/XliffDictionaryProvider.php index f6aa59e..4aafcb4 100644 --- a/src/XliffDictionaryProvider.php +++ b/src/XliffDictionaryProvider.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff; @@ -29,15 +12,29 @@ use CyberSpectrum\I18N\Exception\DictionaryNotFoundException; use CyberSpectrum\I18N\Xliff\Exception\LanguageMismatchException; use CyberSpectrum\I18N\Xliff\Xml\XliffFile; +use InvalidArgumentException; +use Iterator; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; use Psr\Log\NullLogger; +use RuntimeException; +use Symfony\Component\Filesystem\Path; use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; -use Webmozart\PathUtil\Path; +use Traversable; + +use function dirname; +use function file_exists; +use function is_dir; +use function is_readable; +use function is_writable; +use function mkdir; +use function realpath; /** * This provides access to the xliff translations in the store. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class XliffDictionaryProvider implements DictionaryProviderInterface, @@ -46,22 +43,16 @@ class XliffDictionaryProvider implements { use LoggerAwareTrait; - /** - * The root directory. - * - * @var string - */ - private $rootDir; + /** The root directory. */ + private string $rootDir; /** * The directory mask to use when working with subdirectories. * * If not empty, translations will get stored in sub directories naming the source an target language. * If empty, they will get stored in the root directory. - * - * @var string */ - private $subDirectoryMask; + private string $subDirectoryMask; /** * Create a new instance. @@ -69,7 +60,7 @@ class XliffDictionaryProvider implements * @param string $rootDir The root directory. * @param string $subDirectoryMask The sub directory mask to apply. Allowed place holders: "{source}" "{target}". * - * @throws \InvalidArgumentException When the root dir is invalid. + * @throws InvalidArgumentException When the root dir is invalid. */ public function __construct( string $rootDir, @@ -77,23 +68,17 @@ public function __construct( ) { $rootDir = Path::canonicalize($rootDir); if (false === realpath($rootDir) || !is_dir($rootDir)) { - throw new \InvalidArgumentException('Root directory does not exist or is not a directory.'); + throw new InvalidArgumentException('Root directory does not exist or is not a directory.'); } $this->rootDir = realpath($rootDir); $this->subDirectoryMask = $subDirectoryMask; $this->setLogger(new NullLogger()); } - /** - * {@inheritDoc} - * - * @return \Traversable|DictionaryInformation[] - */ - public function getAvailableDictionaries(): \Traversable + public function getAvailableDictionaries(): Traversable { foreach ($this->getFinder() as $fileInfo) { - /** @var SplFileInfo $fileInfo */ - if (is_readable($fileInfo->getPathname())) { + if ($fileInfo->isReadable()) { yield $this->createInformation($fileInfo); } } @@ -105,8 +90,6 @@ public function getAvailableDictionaries(): \Traversable * @param string $name The name of the dictionary. * @param string $sourceLanguage The source language. * @param string $targetLanguage The target language. - * - * @return string */ private function getFileNameFor(string $name, string $sourceLanguage, string $targetLanguage): string { @@ -130,7 +113,9 @@ public function getDictionary( string $targetLanguage, array $customData = [] ): DictionaryInterface { - $this->logger->debug('Xliff: opening dictionary ' . $name); + if ($this->logger) { + $this->logger->debug('Xliff: opening dictionary ' . $name); + } if (!is_readable($fileName = $this->getFileNameFor($name, $sourceLanguage, $targetLanguage))) { throw new DictionaryNotFoundException($name, $sourceLanguage, $targetLanguage); } @@ -140,13 +125,10 @@ public function getDictionary( return $dictionary; } - /** - * {@inheritDoc} - */ - public function getAvailableWritableDictionaries(): \Traversable + public function getAvailableWritableDictionaries(): Traversable { foreach ($this->getFinder() as $fileInfo) { - if (is_writable($fileInfo->getPathname())) { + if ($fileInfo->isWritable()) { yield $this->createInformation($fileInfo); } } @@ -163,7 +145,9 @@ public function getDictionaryForWrite( string $targetLanguage, array $customData = [] ): WritableDictionaryInterface { - $this->logger->debug('Xliff: opening writable dictionary ' . $name); + if ($this->logger) { + $this->logger->debug('Xliff: opening writable dictionary ' . $name); + } if (!file_exists($fileName = $this->getFileNameFor($name, $sourceLanguage, $targetLanguage))) { throw new DictionaryNotFoundException($name, $sourceLanguage, $targetLanguage); } @@ -177,8 +161,8 @@ public function getDictionaryForWrite( /** * {@inheritDoc} * - * @throws \InvalidArgumentException When the dictionary already exists. - * @throws \RuntimeException When the dictionary file can not be created. + * @throws InvalidArgumentException When the dictionary already exists. + * @throws RuntimeException When the dictionary file can not be created. */ public function createDictionary( string $name, @@ -186,17 +170,20 @@ public function createDictionary( string $targetLanguage, array $customData = [] ): WritableDictionaryInterface { - $this->logger->debug('Xliff: creating new dictionary ' . $name); + if ($this->logger) { + $this->logger->debug('Xliff: creating new dictionary ' . $name); + } + if (file_exists($fileName = $this->getFileNameFor($name, $sourceLanguage, $targetLanguage))) { - throw new \InvalidArgumentException('Dictionary ' . $name . ' already exists.'); + throw new InvalidArgumentException('Dictionary ' . $name . ' already exists.'); } if (!is_writable($this->rootDir)) { - throw new \RuntimeException('Dictionary root directory is not writable.'); + throw new RuntimeException('Dictionary root directory is not writable.'); } - if (!is_dir($dir = \dirname($fileName)) && !mkdir($dir) && !is_dir($dir)) { - throw new \RuntimeException(sprintf('Directory "%s" could not be created', $dir)); + if (!is_dir($dir = dirname($fileName)) && !mkdir($dir) && !is_dir($dir)) { + throw new RuntimeException(sprintf('Directory "%s" could not be created', $dir)); } return new WritableXliffDictionary($fileName, $sourceLanguage, $targetLanguage); @@ -206,8 +193,6 @@ public function createDictionary( * Create an information container for the passed xlf file. * * @param SplFileInfo $fileInfo The file info of the xlf file. - * - * @return DictionaryInformation */ private function createInformation(SplFileInfo $fileInfo): DictionaryInformation { @@ -224,9 +209,9 @@ private function createInformation(SplFileInfo $fileInfo): DictionaryInformation /** * Create a finder instance. * - * @return \Iterator + * @return Iterator */ - private function getFinder(): \Iterator + private function getFinder(): Iterator { return Finder::create() ->in($this->rootDir) @@ -243,8 +228,6 @@ private function getFinder(): \Iterator * @param string $targetLanguage The target language. * @param DictionaryInterface $dictionary The dictionary. * - * @return void - * * @throws LanguageMismatchException When the languages do not match the required language. */ private function guardLanguages( @@ -252,8 +235,10 @@ private function guardLanguages( string $targetLanguage, DictionaryInterface $dictionary ): void { - if ($dictionary->getSourceLanguage() !== $sourceLanguage - || $dictionary->getTargetLanguage() !== $targetLanguage) { + if ( + $dictionary->getSourceLanguage() !== $sourceLanguage + || $dictionary->getTargetLanguage() !== $targetLanguage + ) { throw new LanguageMismatchException( $sourceLanguage, $dictionary->getSourceLanguage(), diff --git a/src/XliffTranslationValue.php b/src/XliffTranslationValue.php index 5767daa..39bf4c4 100644 --- a/src/XliffTranslationValue.php +++ b/src/XliffTranslationValue.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff; @@ -30,25 +13,15 @@ */ class XliffTranslationValue implements TranslationValueInterface { - /** - * The dictionary. - * - * @var XliffDictionary - */ - protected $dictionary; + /** The dictionary. */ + protected XliffDictionary $dictionary; - /** - * The XML element of this translation value. - * - * @var XmlElement - */ - protected $node; + /** The XML element of this translation value. */ + protected XmlElement $node; /** - * Create a new instance. - * * @param XliffDictionary $dictionary The dictionary. - * @param XmlElement $node The XML node. + * @param XmlElement $node The XML node. */ public function __construct(XliffDictionary $dictionary, XmlElement $node) { @@ -56,17 +29,11 @@ public function __construct(XliffDictionary $dictionary, XmlElement $node) $this->node = $node; } - /** - * {@inheritDoc} - */ public function getKey(): string { return $this->node->getAttributeNS(XliffFile::XLIFF_NS, 'id'); } - /** - * {@inheritDoc} - */ public function getSource(): ?string { if (($element = $this->getSourceElement()) && $element->firstChild) { @@ -76,9 +43,6 @@ public function getSource(): ?string return null; } - /** - * {@inheritDoc} - */ public function getTarget(): ?string { if (($element = $this->getTargetElement()) && $element->firstChild) { @@ -88,27 +52,17 @@ public function getTarget(): ?string return null; } - /** - * {@inheritDoc} - */ public function isSourceEmpty(): bool { return (null === ($element = $this->getSourceElement()) || null === $element->firstChild); } - /** - * {@inheritDoc} - */ public function isTargetEmpty(): bool { return (null === ($element = $this->getTargetElement()) || null === $element->firstChild); } - /** - * Fetch the target element. - * - * @return XmlElement|null - */ + /** Fetch the source element. */ protected function getSourceElement(): ?XmlElement { $list = $this->node->getElementsByTagNameNS(XliffFile::XLIFF_NS, 'source'); @@ -120,11 +74,7 @@ protected function getSourceElement(): ?XmlElement return null; } - /** - * Fetch the target element. - * - * @return XmlElement|null - */ + /** Fetch the target element. */ protected function getTargetElement(): ?XmlElement { $list = $this->node->getElementsByTagNameNS(XliffFile::XLIFF_NS, 'target'); diff --git a/src/Xml/XliffFile.php b/src/Xml/XliffFile.php index ae10d10..db4e0d0 100644 --- a/src/Xml/XliffFile.php +++ b/src/Xml/XliffFile.php @@ -1,33 +1,30 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Xml; +use DateTime; +use DateTimeImmutable; +use DateTimeInterface; +use DOMDocument; +use DOMElement; +use DOMNode; +use DOMNodeList; +use DOMXPath; +use Generator; +use InvalidArgumentException; +use RuntimeException; + /** * This is an xliff implementation. * * @internal Only to be used within this abstraction. */ -final class XliffFile extends \DOMDocument +final class XliffFile extends DOMDocument { + public const XLIFF_LANGUAGE_PATTERN = '#^[a-zA-Z]{1,8}(-[a-zA-Z\d]{1,8})*$#'; + /** * The xliff Namespace. */ @@ -46,34 +43,35 @@ final class XliffFile extends \DOMDocument public function __construct(string $encoding = 'UTF-8') { parent::__construct('1.0', $encoding); - $this->registerNodeClass('DOMElement', XmlElement::class); + $this->registerNodeClass(DOMElement::class, XmlElement::class); $this->formatOutput = true; $this->preserveWhiteSpace = false; - $root = $this->createElementNS(static::XLIFF_NS, 'xliff'); + $root = $this->createElementNS(self::XLIFF_NS, 'xliff'); $this->appendChild($root); - $this->documentElement->setAttributeNS(static::XLIFF_NS, 'version', '1.2'); - $this->documentElement->appendChild($file = $this->createElementNS(static::XLIFF_NS, 'file')); - $file->appendChild($this->createElementNS(static::XLIFF_NS, 'body')); + /** @psalm-suppress UninitializedProperty - it is initialized in the paren constructor */ + assert($this->documentElement instanceof XmlElement); + $this->documentElement->setAttributeNS(self::XLIFF_NS, 'version', '1.2'); + $this->documentElement->appendChild($file = $this->createElementNS(self::XLIFF_NS, 'file')); + $file->appendChild($this->createElementNS(self::XLIFF_NS, 'body')); // Set some basic information. $this->setDataType('plaintext'); - $this->setDate(new \DateTime()); + $this->setDate(new DateTime()); $this->setOriginal('unspecified source'); $this->setSourceLanguage('en'); $this->setTargetLanguage('en'); } - /** - * Obtain the file element. - * - * @return \DOMElement - */ - public function getFileElement(): \DOMElement + /** Obtain the file element. */ + public function getFileElement(): XmlElement { - return $this->getXPathFirstItem('/xlf:xliff/xlf:file', $this->documentElement); + if (null === $element = $this->getXPathFirstItem('/xlf:xliff/xlf:file', $this->documentElement)) { + throw new RuntimeException('Failed to find file element'); + } + return $element; } /** @@ -84,46 +82,36 @@ public function getFileElement(): \DOMElement * You may use a custom datatype here but have to prefix it with "x-". * * @param string $datatype The data type. - * - * @return void */ - public function setDataType($datatype): void + public function setDataType(string $datatype): void { - $this->getFileElement()->setAttributeNS(static::XLIFF_NS, 'datatype', $datatype); + $this->getFileElement()->setAttributeNS(self::XLIFF_NS, 'datatype', $datatype); } /** * Get the datatype for this file. * * See http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#datatype - * - * @return string */ public function getDataType(): string { - return $this->getFileElement()->getAttributeNS(static::XLIFF_NS, 'datatype'); + return $this->getFileElement()->getAttributeNS(self::XLIFF_NS, 'datatype'); } /** * Sets the last modification time in this file. * - * @param \DateTime $date The date. - * - * @return void + * @param DateTimeInterface $date The date. */ - public function setDate(\DateTime $date): void + public function setDate(DateTimeInterface $date): void { - $this->getFileElement()->setAttributeNS(static::XLIFF_NS, 'date', $date->format(\DateTime::ATOM)); + $this->getFileElement()->setAttributeNS(self::XLIFF_NS, 'date', $date->format(DateTimeInterface::ATOM)); } - /** - * Return the last modification time from this file. - * - * @return \DateTime - */ - public function getDate(): \DateTime + /** Return the last modification time from this file. */ + public function getDate(): DateTimeInterface { - return new \DateTime($this->getFileElement()->getAttributeNS(static::XLIFF_NS, 'date')); + return new DateTimeImmutable($this->getFileElement()->getAttributeNS(self::XLIFF_NS, 'date')); } /** @@ -132,22 +120,16 @@ public function getDate(): \DateTime * You will most likely the file name of the original resource or something like this here. * * @param string $original The name of the original data source. - * - * @return void */ - public function setOriginal($original): void + public function setOriginal(string $original): void { - $this->getFileElement()->setAttributeNS(static::XLIFF_NS, 'original', $original); + $this->getFileElement()->setAttributeNS(self::XLIFF_NS, 'original', $original); } - /** - * Get the original resource name from this file. - * - * @return string - */ + /** Get the original resource name from this file. */ public function getOriginal(): string { - return $this->getFileElement()->getAttributeNS(static::XLIFF_NS, 'original'); + return $this->getFileElement()->getAttributeNS(self::XLIFF_NS, 'original'); } /** @@ -155,16 +137,14 @@ public function getOriginal(): string * * @param string $sourceLanguage The language code from ISO 639-1. * - * @return void - * - * @throws \InvalidArgumentException When the language string is invalid. + * @throws InvalidArgumentException When the language string is invalid. */ - public function setSourceLanguage($sourceLanguage): void + public function setSourceLanguage(string $sourceLanguage): void { - if (!preg_match('#[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*#', $sourceLanguage)) { - throw new \InvalidArgumentException('Invalid language string: "' . $sourceLanguage . '"'); + if (!preg_match(self::XLIFF_LANGUAGE_PATTERN, $sourceLanguage)) { + throw new InvalidArgumentException('Invalid language string: "' . $sourceLanguage . '"'); } - $this->getFileElement()->setAttributeNS(static::XLIFF_NS, 'source-language', $sourceLanguage); + $this->getFileElement()->setAttributeNS(self::XLIFF_NS, 'source-language', $sourceLanguage); } /** @@ -174,7 +154,7 @@ public function setSourceLanguage($sourceLanguage): void */ public function getSourceLanguage(): string { - return $this->getFileElement()->getAttributeNS(static::XLIFF_NS, 'source-language'); + return $this->getFileElement()->getAttributeNS(self::XLIFF_NS, 'source-language'); } /** @@ -182,16 +162,14 @@ public function getSourceLanguage(): string * * @param string $targetLanguage The language code from ISO 639-1. * - * @return void - * - * @throws \InvalidArgumentException When the language string is invalid. + * @throws InvalidArgumentException When the language string is invalid. */ - public function setTargetLanguage($targetLanguage): void + public function setTargetLanguage(string $targetLanguage): void { - if (!preg_match('#[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*#', $targetLanguage)) { - throw new \InvalidArgumentException('Invalid language string: "' . $targetLanguage . '"'); + if (!preg_match(self::XLIFF_LANGUAGE_PATTERN, $targetLanguage)) { + throw new InvalidArgumentException('Invalid language string: "' . $targetLanguage . '"'); } - $this->getFileElement()->setAttributeNS(static::XLIFF_NS, 'target-language', $targetLanguage); + $this->getFileElement()->setAttributeNS(self::XLIFF_NS, 'target-language', $targetLanguage); } /** @@ -201,7 +179,7 @@ public function setTargetLanguage($targetLanguage): void */ public function getTargetLanguage(): string { - return $this->getFileElement()->getAttributeNS(static::XLIFF_NS, 'target-language'); + return $this->getFileElement()->getAttributeNS(self::XLIFF_NS, 'target-language'); } /** @@ -213,27 +191,28 @@ public function getTargetLanguage(): string * * @return XmlElement|null * - * @throws \InvalidArgumentException When the id is empty. + * @throws InvalidArgumentException When the id is empty. */ public function searchTranslationUnit(string $identifier): ?XmlElement { if ('' === $identifier) { - throw new \InvalidArgumentException('Empty Id passed.', 0); + throw new InvalidArgumentException('Empty Id passed.', 0); } - if ($this->documentElement - && $this->documentElement->isDefaultNamespace(self::XLIFF_NS) + if ( + $this->documentElement->isDefaultNamespace(self::XLIFF_NS) && $transUnit = $this->getXPathFirstItem( '/xlf:xliff/xlf:file/xlf:body/xlf:trans-unit[@id=\'' . $identifier . '\']' - )) { - /** @var XmlElement $transUnit */ + ) + ) { return $transUnit; } - if ($transUnit = $this->getXPathFirstItem( - '/xlf:xliff/xlf:file/xlf:body/xlf:trans-unit[@xlf:id=\'' . $identifier . '\']' - )) { - /** @var XmlElement $transUnit */ + if ( + $transUnit = $this->getXPathFirstItem( + '/xlf:xliff/xlf:file/xlf:body/xlf:trans-unit[@xlf:id=\'' . $identifier . '\']' + ) + ) { return $transUnit; } @@ -243,17 +222,17 @@ public function searchTranslationUnit(string $identifier): ?XmlElement /** * Append a translation unit. * - * @param string $identifier The identifier to set. - * @param string $sourceValue The content for the source value to set. + * @param string $identifier The identifier to set. + * @param string|null $sourceValue The content for the source value to set. * * @return XmlElement * - * @throws \InvalidArgumentException When the body element can not be found. + * @throws InvalidArgumentException When the body element can not be found. */ public function createTranslationUnit(string $identifier, string $sourceValue = null): XmlElement { if (null === $body = $this->getXPathFirstItem('/xlf:xliff/xlf:file/xlf:body')) { - throw new \InvalidArgumentException('Could not find the xliff body element'); + throw new InvalidArgumentException('Could not find the xliff body element'); } /** @var XmlElement $transUnit */ @@ -273,34 +252,30 @@ public function createTranslationUnit(string $identifier, string $sourceValue = /** * Obtain all keys within the dictionary. * - * @return \Generator + * @return Generator * - * @throws \RuntimeException When the id is empty. + * @throws RuntimeException When the id is empty. */ - public function extractTranslationKeys(): \Generator + public function extractTranslationKeys(): Generator { - /** @var \DOMNodeList $tmp */ + /** @var DOMNodeList $tmp */ $transUnits = $this->getXPath()->query('/xlf:xliff/xlf:file/xlf:body/xlf:trans-unit'); if ($transUnits->length > 0) { - /** @var \DOMElement $element */ + /** @var DOMElement $element */ foreach ($transUnits as $element) { if ('' === $key = $element->getAttributeNS(self::XLIFF_NS, 'id')) { - throw new \RuntimeException('Empty Id: ' . var_export($element, true)); + throw new RuntimeException('Empty Id: ' . var_export($element, true)); } yield $key; } } } - /** - * Creates a new XPath object for the doc with the namespace xliff registered. - * - * @return \DOMXPath - */ - private function getXPath(): \DOMXPath + /** Creates a new XPath object for the doc with the namespace xliff registered. */ + private function getXPath(): DOMXPath { - $xpath = new \DOMXPath($this); + $xpath = new DOMXPath($this); $xpath->registerNamespace('xlf', self::XLIFF_NS); return $xpath; @@ -309,16 +284,17 @@ private function getXPath(): \DOMXPath /** * Perform a Xpath search with the given query and return the first match if found. * - * @param string $query The query to use. - * @param null $contextNode The context node to apply. - * - * @return \DOMElement|\DOMNode|null + * @param string $query The query to use. + * @param DOMNode|null $contextNode The context node to apply. */ - private function getXPathFirstItem($query, $contextNode = null) + private function getXPathFirstItem(string $query, ?DOMNode $contextNode = null): ?XmlElement { - /** @var \DOMNodeList $tmp */ + /** @var DOMNodeList $tmp */ $tmp = $this->getXPath()->query($query, $contextNode); - return $tmp->length ? $tmp->item(0) : null; + $item = $tmp->item(0); + assert(null === $item || $item instanceof XmlElement); + + return $item; } } diff --git a/src/Xml/XmlElement.php b/src/Xml/XmlElement.php index c0b930d..f3f2e44 100644 --- a/src/Xml/XmlElement.php +++ b/src/Xml/XmlElement.php @@ -1,32 +1,24 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Xml; +use DOMDocument; +use DOMElement; + +use function array_slice; +use function call_user_func_array; +use function func_get_args; + /** * This is an xliff element implementation. * * @internal Only to be used within this abstraction. + * + * @property DOMDocument $ownerDocument */ -final class XmlElement extends \DOMElement +final class XmlElement extends DOMElement { /** * Adds new attribute. @@ -34,7 +26,7 @@ final class XmlElement extends \DOMElement * Work around method for the fact that DOMDocument adds some mysterious namespache "xmlns:default" * when the root NS is the requested XMLNS and setAttributeNS() is used. * - * @param string $namespaceURI The namespace URI. + * @param string $namespace The namespace URI. * @param string $qualifiedName The qualified name of the attribute, as prefix:tagname. * @param string $value The value of the attribute. * @@ -42,16 +34,17 @@ final class XmlElement extends \DOMElement * * @link https://php.net/manual/en/domelement.setattributens.php */ - public function setAttributeNS($namespaceURI, $qualifiedName, $value): void + public function setAttributeNS($namespace, $qualifiedName, $value): void { - if ($this->ownerDocument - && $namespaceURI === XliffFile::XLIFF_NS - && $this->ownerDocument->isDefaultNamespace(XliffFile::XLIFF_NS)) { - \call_user_func_array(['parent', 'setAttribute'], \array_slice(\func_get_args(), 1)); + if ( + $namespace === XliffFile::XLIFF_NS + && $this->ownerDocument->isDefaultNamespace(XliffFile::XLIFF_NS) + ) { + call_user_func_array(['parent', 'setAttribute'], array_slice(func_get_args(), 1)); return; } - \call_user_func_array(['parent', 'setAttributeNS'], \func_get_args()); + call_user_func_array(['parent', 'setAttributeNS'], func_get_args()); } /** @@ -60,22 +53,27 @@ public function setAttributeNS($namespaceURI, $qualifiedName, $value): void * Work around method for the fact that DOMDocument adds some mysterious namespache "xmlns:default" * when the root NS is the requested XMLNS and setAttributeNS() is used. * - * @param string $namespaceURI The namespace URI. - * @param string $localName The local name. + * @param string $namespace The namespace URI. + * @param string $localName The local name. * * @return string The value of the attribute, or an empty string if no attribute with the given localName and * namespaceURI is found. * * @link https://php.net/manual/en/domelement.getattributens.php + * + * @psalm-suppress MixedInferredReturnType */ - public function getAttributeNS($namespaceURI, $localName): ?string + public function getAttributeNS($namespace, $localName): string { - if ($this->ownerDocument - && $namespaceURI === XliffFile::XLIFF_NS - && $this->ownerDocument->isDefaultNamespace(XliffFile::XLIFF_NS)) { - return \call_user_func_array(['parent', 'getAttribute'], \array_slice(\func_get_args(), 1)); + if ( + $namespace === XliffFile::XLIFF_NS + && $this->ownerDocument->isDefaultNamespace(XliffFile::XLIFF_NS) + ) { + /** @psalm-suppress MixedReturnStatement */ + return call_user_func_array(['parent', 'getAttribute'], array_slice(func_get_args(), 1)); } - return \call_user_func_array(['parent', 'getAttributeNS'], \func_get_args()); + /** @psalm-suppress MixedReturnStatement */ + return call_user_func_array(['parent', 'getAttributeNS'], func_get_args()); } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 82a44c3..3048fd0 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Test; @@ -28,12 +11,8 @@ */ class TestCase extends \PHPUnit\Framework\TestCase { - /** - * Temp dir name. - * - * @var string - */ - private $dirName; + /** Temp dir name. */ + private ?string $dirName = null; /** * {@inheritDoc} diff --git a/tests/WritableXliffDictionaryTest.php b/tests/WritableXliffDictionaryTest.php index 089a4a1..b082bee 100644 --- a/tests/WritableXliffDictionaryTest.php +++ b/tests/WritableXliffDictionaryTest.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Test; @@ -27,56 +10,46 @@ use CyberSpectrum\I18N\Xliff\WritableXliffTranslationValue; use CyberSpectrum\I18N\Xliff\XliffTranslationValue; +use function iterator_to_array; + /** - * This tests the writable dictionary. - * * @covers \CyberSpectrum\I18N\Xliff\WritableXliffDictionary * @covers \CyberSpectrum\I18N\Xliff\XliffTranslationValue * @covers \CyberSpectrum\I18N\Xliff\WritableXliffTranslationValue */ class WritableXliffDictionaryTest extends TestCase { - /** - * Test. - * - * @return void - */ public function testInstantiation(): void { $dictionary = new WritableXliffDictionary($this->provide(__DIR__ . '/Fixtures/without-subdir') . '/test1.xlf'); - $this->assertSame('en', $dictionary->getSourceLanguage()); - $this->assertSame('de', $dictionary->getTargetLanguage()); - $this->assertSame( + self::assertSame('en', $dictionary->getSourceLanguage()); + self::assertSame('de', $dictionary->getTargetLanguage()); + self::assertSame( ['test-string-with-only-source', 'test-string-with-source-and-target'], - \iterator_to_array($dictionary->keys()) + iterator_to_array($dictionary->keys()) ); - $this->assertInstanceOf( + self::assertInstanceOf( XliffTranslationValue::class, $value = $dictionary->get('test-string-with-only-source') ); - $this->assertSame('test-string-with-only-source', $value->getKey()); - $this->assertSame('The source value', $value->getSource()); - $this->assertNull($value->getTarget()); - $this->assertFalse($value->isSourceEmpty()); - $this->assertTrue($value->isTargetEmpty()); + self::assertSame('test-string-with-only-source', $value->getKey()); + self::assertSame('The source value', $value->getSource()); + self::assertNull($value->getTarget()); + self::assertFalse($value->isSourceEmpty()); + self::assertTrue($value->isTargetEmpty()); - $this->assertInstanceOf( + self::assertInstanceOf( XliffTranslationValue::class, $value = $dictionary->get('test-string-with-source-and-target') ); - $this->assertSame('test-string-with-source-and-target', $value->getKey()); - $this->assertSame('The source value', $value->getSource()); - $this->assertSame('The target value', $value->getTarget()); - $this->assertFalse($value->isSourceEmpty()); - $this->assertFalse($value->isTargetEmpty()); + self::assertSame('test-string-with-source-and-target', $value->getKey()); + self::assertSame('The source value', $value->getSource()); + self::assertSame('The target value', $value->getTarget()); + self::assertFalse($value->isSourceEmpty()); + self::assertFalse($value->isTargetEmpty()); } - /** - * Test. - * - * @return void - */ public function testThrowsForUnknownKey(): void { $dictionary = new WritableXliffDictionary($this->provide(__DIR__ . '/Fixtures/without-subdir') . '/test1.xlf'); @@ -87,30 +60,20 @@ public function testThrowsForUnknownKey(): void $dictionary->getWritable('unknown-key'); } - /** - * Test. - * - * @return void - */ public function testAddingValuesWorks(): void { $dictionary = new WritableXliffDictionary($fileName = $this->getTempFile()); - $this->assertInstanceOf(WritableXliffTranslationValue::class, $value = $dictionary->add('test-key-add')); - $this->assertSame(['test-key-add'], \iterator_to_array($dictionary->keys())); - $this->assertSame('test-key-add', $value->getKey()); - $this->assertNull($value->getSource()); - $this->assertNull($value->getTarget()); - $this->assertTrue($value->isSourceEmpty()); - $this->assertTrue($value->isTargetEmpty()); - $this->assertFileExists($fileName); + self::assertInstanceOf(WritableXliffTranslationValue::class, $value = $dictionary->add('test-key-add')); + self::assertSame(['test-key-add'], iterator_to_array($dictionary->keys())); + self::assertSame('test-key-add', $value->getKey()); + self::assertNull($value->getSource()); + self::assertNull($value->getTarget()); + self::assertTrue($value->isSourceEmpty()); + self::assertTrue($value->isTargetEmpty()); + self::assertFileExists($fileName); } - /** - * Test. - * - * @return void - */ public function testAddingExistingValuesThrows(): void { $dictionary = new WritableXliffDictionary($this->getTempFile()); @@ -122,11 +85,6 @@ public function testAddingExistingValuesThrows(): void $dictionary->add('test-key'); } - /** - * Test. - * - * @return void - */ public function testRemovalOfValuesWorks(): void { $dictionary = new WritableXliffDictionary($fileName = $this->getTempFile()); @@ -134,16 +92,11 @@ public function testRemovalOfValuesWorks(): void $dictionary->remove('test-key'); - $this->assertSame([], \iterator_to_array($dictionary->keys())); - $this->assertFalse($dictionary->has('test-key')); - $this->assertFileExists($fileName); + self::assertSame([], iterator_to_array($dictionary->keys())); + self::assertFalse($dictionary->has('test-key')); + self::assertFileExists($fileName); } - /** - * Test. - * - * @return void - */ public function testRemovalOfNonExistentValueThrows(): void { $dictionary = new WritableXliffDictionary($this->getTempFile()); @@ -154,33 +107,23 @@ public function testRemovalOfNonExistentValueThrows(): void $dictionary->remove('unknown-key'); } - /** - * Test. - * - * @return void - */ public function testWritingValuesWorks(): void { $dictionary = new WritableXliffDictionary($fileName = $this->getTempFile()); $dictionary->add('test-key'); - $this->assertInstanceOf(WritableXliffTranslationValue::class, $value = $dictionary->getWritable('test-key')); + self::assertInstanceOf(WritableXliffTranslationValue::class, $value = $dictionary->getWritable('test-key')); $value->setSource('source value'); $value->setTarget('target value'); unset($value); $test = $dictionary->get('test-key'); - $this->assertSame('source value', $test->getSource()); - $this->assertSame('target value', $test->getTarget()); - $this->assertFileExists($fileName); + self::assertSame('source value', $test->getSource()); + self::assertSame('target value', $test->getTarget()); + self::assertFileExists($fileName); } - /** - * Test. - * - * @return void - */ public function testWritingThrowsForUnknown(): void { $dictionary = new WritableXliffDictionary($this->getTempFile()); diff --git a/tests/WritableXliffTranslationValueTest.php b/tests/WritableXliffTranslationValueTest.php index 53c0a2c..0ab3744 100644 --- a/tests/WritableXliffTranslationValueTest.php +++ b/tests/WritableXliffTranslationValueTest.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Test; @@ -25,83 +8,60 @@ use CyberSpectrum\I18N\Xliff\WritableXliffTranslationValue; use CyberSpectrum\I18N\Xliff\Xml\XliffFile; use CyberSpectrum\I18N\Xliff\Xml\XmlElement; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -/** - * This tests the simple translation value. - * - * @covers \CyberSpectrum\I18N\Xliff\WritableXliffTranslationValue - */ +/** @covers \CyberSpectrum\I18N\Xliff\WritableXliffTranslationValue */ class WritableXliffTranslationValueTest extends TestCase { - /** - * Test. - * - * @return void - */ public function testEmptyValue(): void { $value = new WritableXliffTranslationValue($this->mockDictionary(), $this->mockElement('test-key')); - $this->assertSame('test-key', $value->getKey()); - $this->assertNull($value->getSource()); - $this->assertNull($value->getTarget()); - $this->assertTrue($value->isSourceEmpty()); - $this->assertTrue($value->isTargetEmpty()); + self::assertSame('test-key', $value->getKey()); + self::assertNull($value->getSource()); + self::assertNull($value->getTarget()); + self::assertTrue($value->isSourceEmpty()); + self::assertTrue($value->isTargetEmpty()); } - /** - * Test. - * - * @return void - */ public function testCreatingWithValuesWorks(): void { $element = $this->mockElement('test-key', 'Source value', 'Target value'); $value = new WritableXliffTranslationValue($this->mockDictionary(), $element); - $this->assertSame('Source value', $value->getSource()); - $this->assertSame('Target value', $value->getTarget()); - $this->assertFalse($value->isSourceEmpty()); - $this->assertFalse($value->isTargetEmpty()); + self::assertSame('Source value', $value->getSource()); + self::assertSame('Target value', $value->getTarget()); + self::assertFalse($value->isSourceEmpty()); + self::assertFalse($value->isTargetEmpty()); } - /** - * Test. - * - * @return void - */ public function testSettingValuesWorks(): void { $element = $this->mockElement('test-key'); $value = new WritableXliffTranslationValue($this->mockDictionary(2), $element); - $this->assertSame($value, $value->setSource('Source value')); - $this->assertSame($value, $value->setTarget('Target value')); + $value->setSource('Source value'); + $value->setTarget('Target value'); - $this->assertSame('Source value', $value->getSource()); - $this->assertSame('Target value', $value->getTarget()); - $this->assertFalse($value->isSourceEmpty()); - $this->assertFalse($value->isTargetEmpty()); + self::assertSame('Source value', $value->getSource()); + self::assertSame('Target value', $value->getTarget()); + self::assertFalse($value->isSourceEmpty()); + self::assertFalse($value->isTargetEmpty()); } - /** - * Test. - * - * @return void - */ public function testClearingValuesWorks(): void { $element = $this->mockElement('test-key', 'Source value', 'Target value'); $value = new WritableXliffTranslationValue($this->mockDictionary(), $element); - $this->assertSame($value, $value->clearSource()); - $this->assertSame($value, $value->clearTarget()); + $value->clearSource(); + $value->clearTarget(); - $this->assertNull($value->getSource()); - $this->assertNull($value->getTarget()); - $this->assertTrue($value->isSourceEmpty()); - $this->assertTrue($value->isTargetEmpty()); + self::assertNull($value->getSource()); + self::assertNull($value->getTarget()); + self::assertTrue($value->isSourceEmpty()); + self::assertTrue($value->isTargetEmpty()); } /** @@ -109,13 +69,13 @@ public function testClearingValuesWorks(): void * * @param int $expectedChangeCount Expected count how often "markChanged" should be triggered. * - * @return \PHPUnit\Framework\MockObject\MockObject|WritableXliffDictionary + * @return MockObject|WritableXliffDictionary */ - private function mockDictionary($expectedChangeCount = 0): WritableXliffDictionary + private function mockDictionary(int $expectedChangeCount = 0): WritableXliffDictionary { $mock = $this ->getMockBuilder(WritableXliffDictionary::class) - ->setMethods(['markChanged']) + ->onlyMethods(['markChanged']) ->disableOriginalConstructor() ->getMock(); if ($expectedChangeCount > 0) { diff --git a/tests/XliffDictionaryDefinitionBuilderTest.php b/tests/XliffDictionaryDefinitionBuilderTest.php index 8f6bf48..7feee79 100644 --- a/tests/XliffDictionaryDefinitionBuilderTest.php +++ b/tests/XliffDictionaryDefinitionBuilderTest.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Test; @@ -26,18 +9,9 @@ use CyberSpectrum\I18N\Xliff\XliffDictionaryDefinitionBuilder; use PHPUnit\Framework\TestCase; -/** - * This tests the copy job builder. - * - * @covers \CyberSpectrum\I18N\Xliff\XliffDictionaryDefinitionBuilder - */ +/** @covers \CyberSpectrum\I18N\Xliff\XliffDictionaryDefinitionBuilder */ class XliffDictionaryDefinitionBuilderTest extends TestCase { - /** - * Test. - * - * @return void - */ public function testBuilding(): void { $configuration = new Configuration(); @@ -52,7 +26,7 @@ public function testBuilding(): void 'name' => 'test', ]); - $this->assertInstanceOf(DictionaryDefinition::class, $dictionary); - $this->assertSame('test', $dictionary->getName()); + self::assertInstanceOf(DictionaryDefinition::class, $dictionary); + self::assertSame('test', $dictionary->getName()); } } diff --git a/tests/XliffDictionaryProviderTest.php b/tests/XliffDictionaryProviderTest.php index 23f3295..3102372 100644 --- a/tests/XliffDictionaryProviderTest.php +++ b/tests/XliffDictionaryProviderTest.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Test; @@ -26,12 +9,12 @@ use CyberSpectrum\I18N\Xliff\WritableXliffDictionary; use CyberSpectrum\I18N\Xliff\XliffDictionary; use CyberSpectrum\I18N\Xliff\XliffDictionaryProvider; +use InvalidArgumentException; +use RuntimeException; -/** - * This tests the xliff provider. - * - * @covers \CyberSpectrum\I18N\Xliff\XliffDictionaryProvider - */ +use function iterator_to_array; + +/** @covers \CyberSpectrum\I18N\Xliff\XliffDictionaryProvider */ class XliffDictionaryProviderTest extends TestCase { /** @@ -53,8 +36,6 @@ public function dictionaryProviderProvider(): array * @param string $fixtures The fixtures directory. * @param string $subDirs The sub directory mask. * - * @return void - * * @dataProvider dictionaryProviderProvider */ public function testGetAvailableDictionariesFromFixturesDirectory(string $fixtures, string $subDirs): void @@ -62,10 +43,10 @@ public function testGetAvailableDictionariesFromFixturesDirectory(string $fixtur $provider = new XliffDictionaryProvider($this->provide($fixtures), $subDirs); /** @var DictionaryInformation[] $descriptions */ - $this->assertCount(1, $descriptions = \iterator_to_array($provider->getAvailableDictionaries())); - $this->assertSame('test1', $descriptions[0]->getName()); - $this->assertSame('en', $descriptions[0]->getSourceLanguage()); - $this->assertSame('de', $descriptions[0]->getTargetLanguage()); + self::assertCount(1, $descriptions = iterator_to_array($provider->getAvailableDictionaries())); + self::assertSame('test1', $descriptions[0]->getName()); + self::assertSame('en', $descriptions[0]->getSourceLanguage()); + self::assertSame('de', $descriptions[0]->getTargetLanguage()); } /** @@ -74,15 +55,13 @@ public function testGetAvailableDictionariesFromFixturesDirectory(string $fixtur * @param string $fixtures The fixtures directory. * @param string $subDirs The sub directory mask. * - * @return void - * * @dataProvider dictionaryProviderProvider */ public function testGetFromFixturesDirectory(string $fixtures, string $subDirs): void { $provider = new XliffDictionaryProvider($this->provide($fixtures), $subDirs); - $this->assertInstanceOf(XliffDictionary::class, $provider->getDictionary('test1', 'en', 'de')); + self::assertInstanceOf(XliffDictionary::class, $provider->getDictionary('test1', 'en', 'de')); } /** @@ -91,8 +70,6 @@ public function testGetFromFixturesDirectory(string $fixtures, string $subDirs): * @param string $fixtures The fixtures directory. * @param string $subDirs The sub directory mask. * - * @return void - * * @dataProvider dictionaryProviderProvider */ public function testThrowsForUnknownDictionary(string $fixtures, string $subDirs): void @@ -113,8 +90,6 @@ public function testThrowsForUnknownDictionary(string $fixtures, string $subDirs * @param string $fixtures The fixtures directory. * @param string $subDirs The sub directory mask. * - * @return void - * * @dataProvider dictionaryProviderProvider */ public function testGetAvailableWritableDictionariesFromFixturesDirectory(string $fixtures, string $subDirs): void @@ -122,10 +97,10 @@ public function testGetAvailableWritableDictionariesFromFixturesDirectory(string $provider = new XliffDictionaryProvider($this->provide($fixtures), $subDirs); /** @var DictionaryInformation[] $descriptions */ - $this->assertCount(1, $descriptions = \iterator_to_array($provider->getAvailableWritableDictionaries())); - $this->assertSame('test1', $descriptions[0]->getName()); - $this->assertSame('en', $descriptions[0]->getSourceLanguage()); - $this->assertSame('de', $descriptions[0]->getTargetLanguage()); + self::assertCount(1, $descriptions = iterator_to_array($provider->getAvailableWritableDictionaries())); + self::assertSame('test1', $descriptions[0]->getName()); + self::assertSame('en', $descriptions[0]->getSourceLanguage()); + self::assertSame('de', $descriptions[0]->getTargetLanguage()); } /** @@ -134,15 +109,13 @@ public function testGetAvailableWritableDictionariesFromFixturesDirectory(string * @param string $fixtures The fixtures directory. * @param string $subDirs The sub directory mask. * - * @return void - * * @dataProvider dictionaryProviderProvider */ public function testGetWritable(string $fixtures, string $subDirs): void { $provider = new XliffDictionaryProvider($this->provide($fixtures), $subDirs); - $this->assertInstanceOf(WritableXliffDictionary::class, $provider->getDictionaryForWrite('test1', 'en', 'de')); + self::assertInstanceOf(WritableXliffDictionary::class, $provider->getDictionaryForWrite('test1', 'en', 'de')); } /** @@ -151,8 +124,6 @@ public function testGetWritable(string $fixtures, string $subDirs): void * @param string $fixtures The fixtures directory. * @param string $subDirs The sub directory mask. * - * @return void - * * @dataProvider dictionaryProviderProvider */ public function testThrowsForUnknownDictionaryForWrite(string $fixtures, string $subDirs): void @@ -173,15 +144,13 @@ public function testThrowsForUnknownDictionaryForWrite(string $fixtures, string * @param string $fixtures The fixtures directory. * @param string $subDirs The sub directory mask. * - * @return void - * * @dataProvider dictionaryProviderProvider */ public function testCreateDictionary(string $fixtures, string $subDirs): void { $provider = new XliffDictionaryProvider($this->provide($fixtures), $subDirs); - $this->assertInstanceOf(WritableXliffDictionary::class, $provider->createDictionary('create-new', 'en', 'de')); + self::assertInstanceOf(WritableXliffDictionary::class, $provider->createDictionary('create-new', 'en', 'de')); } /** @@ -190,30 +159,23 @@ public function testCreateDictionary(string $fixtures, string $subDirs): void * @param string $fixtures The fixtures directory. * @param string $subDirs The sub directory mask. * - * @return void - * * @dataProvider dictionaryProviderProvider */ public function testThrowsForExistingDictionary(string $fixtures, string $subDirs): void { $provider = new XliffDictionaryProvider($this->provide($fixtures), $subDirs); - $this->expectException(\InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Dictionary test1 already exists.'); $provider->createDictionary('test1', 'en', 'de'); } - /** - * Test. - * - * @return void - */ public function testThrowsForUnwritableRootDir(): void { $provider = new XliffDictionaryProvider('/'); - $this->expectException(\RuntimeException::class); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Dictionary root directory is not writable.'); $provider->createDictionary('test1', 'en', 'de'); diff --git a/tests/XliffDictionaryTest.php b/tests/XliffDictionaryTest.php index 17227c0..6ccf080 100644 --- a/tests/XliffDictionaryTest.php +++ b/tests/XliffDictionaryTest.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Test; @@ -26,54 +9,42 @@ use CyberSpectrum\I18N\Xliff\XliffTranslationValue; /** - * This tests the simple translation value. - * * @covers \CyberSpectrum\I18N\Xliff\XliffDictionary * @covers \CyberSpectrum\I18N\Xliff\XliffTranslationValue */ class XliffDictionaryTest extends TestCase { - /** - * Test. - * - * @return void - */ public function testInstantiation(): void { $dictionary = new XliffDictionary($this->provide(__DIR__ . '/Fixtures/without-subdir') . '/test1.xlf'); - $this->assertSame('en', $dictionary->getSourceLanguage()); - $this->assertSame('de', $dictionary->getTargetLanguage()); - $this->assertSame( + self::assertSame('en', $dictionary->getSourceLanguage()); + self::assertSame('de', $dictionary->getTargetLanguage()); + self::assertSame( ['test-string-with-only-source', 'test-string-with-source-and-target'], \iterator_to_array($dictionary->keys()) ); - $this->assertInstanceOf( + self::assertInstanceOf( XliffTranslationValue::class, $value = $dictionary->get('test-string-with-only-source') ); - $this->assertSame('test-string-with-only-source', $value->getKey()); - $this->assertSame('The source value', $value->getSource()); - $this->assertNull($value->getTarget()); - $this->assertFalse($value->isSourceEmpty()); - $this->assertTrue($value->isTargetEmpty()); + self::assertSame('test-string-with-only-source', $value->getKey()); + self::assertSame('The source value', $value->getSource()); + self::assertNull($value->getTarget()); + self::assertFalse($value->isSourceEmpty()); + self::assertTrue($value->isTargetEmpty()); - $this->assertInstanceOf( + self::assertInstanceOf( XliffTranslationValue::class, $value = $dictionary->get('test-string-with-source-and-target') ); - $this->assertSame('test-string-with-source-and-target', $value->getKey()); - $this->assertSame('The source value', $value->getSource()); - $this->assertSame('The target value', $value->getTarget()); - $this->assertFalse($value->isSourceEmpty()); - $this->assertFalse($value->isTargetEmpty()); + self::assertSame('test-string-with-source-and-target', $value->getKey()); + self::assertSame('The source value', $value->getSource()); + self::assertSame('The target value', $value->getTarget()); + self::assertFalse($value->isSourceEmpty()); + self::assertFalse($value->isTargetEmpty()); } - /** - * Test. - * - * @return void - */ public function testThrowsForUnknownKey(): void { $dictionary = new XliffDictionary($this->provide(__DIR__ . '/Fixtures/without-subdir') . '/test1.xlf'); diff --git a/tests/XliffTranslationValueTest.php b/tests/XliffTranslationValueTest.php index 6e17a32..fed6c0b 100644 --- a/tests/XliffTranslationValueTest.php +++ b/tests/XliffTranslationValueTest.php @@ -1,23 +1,6 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Test; @@ -25,57 +8,43 @@ use CyberSpectrum\I18N\Xliff\XliffTranslationValue; use CyberSpectrum\I18N\Xliff\Xml\XliffFile; use CyberSpectrum\I18N\Xliff\Xml\XmlElement; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -/** - * This tests the simple translation value. - * - * @covers \CyberSpectrum\I18N\Xliff\XliffTranslationValue - */ +/** @covers \CyberSpectrum\I18N\Xliff\XliffTranslationValue */ class XliffTranslationValueTest extends TestCase { - /** - * Test. - * - * @return void - */ public function testEmptyValue(): void { $value = new XliffTranslationValue($this->mockDictionary(), $this->mockElement('test-key')); - $this->assertSame('test-key', $value->getKey()); - $this->assertNull($value->getSource()); - $this->assertNull($value->getTarget()); - $this->assertTrue($value->isSourceEmpty()); - $this->assertTrue($value->isTargetEmpty()); + self::assertSame('test-key', $value->getKey()); + self::assertNull($value->getSource()); + self::assertNull($value->getTarget()); + self::assertTrue($value->isSourceEmpty()); + self::assertTrue($value->isTargetEmpty()); } - /** - * Test. - * - * @return void - */ public function testCreatingWithValuesWorks(): void { $element = $this->mockElement('test-key', 'Source value', 'Target value'); $value = new XliffTranslationValue($this->mockDictionary(), $element); - $this->assertSame('Source value', $value->getSource()); - $this->assertSame('Target value', $value->getTarget()); - $this->assertFalse($value->isSourceEmpty()); - $this->assertFalse($value->isTargetEmpty()); + self::assertSame('Source value', $value->getSource()); + self::assertSame('Target value', $value->getTarget()); + self::assertFalse($value->isSourceEmpty()); + self::assertFalse($value->isTargetEmpty()); } /** * Mock a dictionary. * - * @return \PHPUnit\Framework\MockObject\MockObject|XliffDictionary + * @return MockObject|XliffDictionary */ private function mockDictionary(): XliffDictionary { $mock = $this ->getMockBuilder(XliffDictionary::class) - ->setMethods(['markChanged']) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/Xml/XliffFileTest.php b/tests/Xml/XliffFileTest.php index 6503196..a30a777 100644 --- a/tests/Xml/XliffFileTest.php +++ b/tests/Xml/XliffFileTest.php @@ -1,70 +1,46 @@ - * @copyright 2018 CyberSpectrum. - * @license https://github.com/cyberspectrum/i18n-xliff/blob/master/LICENSE MIT - * @filesource - */ - -declare(strict_types = 1); +declare(strict_types=1); namespace CyberSpectrum\I18N\Xliff\Test\Xml; use CyberSpectrum\I18N\Xliff\Xml\XliffFile; +use DateTimeInterface; +use DOMText; +use InvalidArgumentException; use PHPUnit\Framework\TestCase; -/** - * This tests the xliff file. - */ +use function iterator_to_array; + +/** @covers \CyberSpectrum\I18N\Xliff\Xml\XliffFile */ class XliffFileTest extends TestCase { - /** - * Test. - * - * @return void - */ public function testBasicDocumentContainsValidDefaults(): void { $xliff = new XliffFile(); - $this->assertSame('plaintext', $xliff->getDataType()); - $this->assertSame(date(\DateTime::ATOM), $xliff->getDate()->format(\DateTime::ATOM)); - $this->assertSame('unspecified source', $xliff->getOriginal()); - $this->assertSame('en', $xliff->getSourceLanguage()); - $this->assertSame('en', $xliff->getTargetLanguage()); + self::assertSame('plaintext', $xliff->getDataType()); + self::assertSame(date(DateTimeInterface::ATOM), $xliff->getDate()->format(DateTimeInterface::ATOM)); + self::assertSame('unspecified source', $xliff->getOriginal()); + self::assertSame('en', $xliff->getSourceLanguage()); + self::assertSame('en', $xliff->getTargetLanguage()); $rootNode = $xliff->documentElement; - $this->assertTrue($xliff->isDefaultNamespace(XliffFile::XLIFF_NS)); - $this->assertSame('xliff', $rootNode->localName); - $this->assertSame(XliffFile::XLIFF_NS, $rootNode->namespaceURI); - $this->assertSame('1.2', $rootNode->getAttributeNS(XliffFile::XLIFF_NS, 'version')); + self::assertTrue($xliff->isDefaultNamespace(XliffFile::XLIFF_NS)); + self::assertSame('xliff', $rootNode->localName); + self::assertSame(XliffFile::XLIFF_NS, $rootNode->namespaceURI); + self::assertSame('1.2', $rootNode->getAttributeNS(XliffFile::XLIFF_NS, 'version')); $file = $rootNode->firstChild; - $this->assertSame('file', $file->localName); - $this->assertSame(XliffFile::XLIFF_NS, $file->namespaceURI); + self::assertSame('file', $file->localName); + self::assertSame(XliffFile::XLIFF_NS, $file->namespaceURI); $body = $file->firstChild; - $this->assertSame('body', $body->localName); - $this->assertSame(XliffFile::XLIFF_NS, $body->namespaceURI); + self::assertSame('body', $body->localName); + self::assertSame(XliffFile::XLIFF_NS, $body->namespaceURI); - $this->assertSame(XliffFile::XLIFF_NS, $rootNode->namespaceURI); - $this->assertSame(XliffFile::XLIFF_NS, $xliff->lookupNamespaceUri(null)); + self::assertSame(XliffFile::XLIFF_NS, $rootNode->namespaceURI); + self::assertSame(XliffFile::XLIFF_NS, $xliff->lookupNamespaceUri(null)); } - /** - * Test. - * - * @return void - */ public function testAddingUnitContainsValidDefaults(): void { $xliff = new XliffFile(); @@ -72,68 +48,48 @@ public function testAddingUnitContainsValidDefaults(): void $xliff->createTranslationUnit('test', 'temp'); $unit = $xliff->documentElement->firstChild->firstChild->firstChild; - $this->assertSame('trans-unit', $unit->localName); - $this->assertSame(XliffFile::XLIFF_NS, $unit->namespaceURI); - $this->assertSame('test', $unit->getAttributeNS(XliffFile::XLIFF_NS, 'id')); + self::assertSame('trans-unit', $unit->localName); + self::assertSame(XliffFile::XLIFF_NS, $unit->namespaceURI); + self::assertSame('test', $unit->getAttributeNS(XliffFile::XLIFF_NS, 'id')); $source = $unit->firstChild; - $this->assertSame('source', $source->localName); - $this->assertSame(XliffFile::XLIFF_NS, $source->namespaceURI); - $this->assertInstanceOf(\DOMText::class, $source->firstChild); - $this->assertSame('temp', $source->textContent); + self::assertSame('source', $source->localName); + self::assertSame(XliffFile::XLIFF_NS, $source->namespaceURI); + self::assertInstanceOf(DOMText::class, $source->firstChild); + self::assertSame('temp', $source->textContent); } - /** - * Test. - * - * @return void - */ public function testSearchTranslationUnit(): void { $xliff = new XliffFile(); $xliff->createTranslationUnit('test', 'temp'); $unit = $xliff->documentElement->firstChild->firstChild->firstChild; - $this->assertSame($unit, $xliff->searchTranslationUnit('test')); + self::assertSame($unit, $xliff->searchTranslationUnit('test')); } - /** - * Test. - * - * @return void - */ public function testSearchTranslationUnitThrowsForEmptyId(): void { $xliff = new XliffFile(); - $this->expectException(\InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Empty Id passed'); $xliff->searchTranslationUnit(''); } - /** - * Test. - * - * @return void - */ public function testSearchTranslationUnitReturnsNullForUnknown(): void { $xliff = new XliffFile(); - $this->assertNull($xliff->searchTranslationUnit('test')); + self::assertNull($xliff->searchTranslationUnit('test')); } - /** - * Test. - * - * @return void - */ public function testExtractTranslationKeys(): void { $xliff = new XliffFile(); $xliff->createTranslationUnit('test1', 'temp'); $xliff->createTranslationUnit('test2', 'temp'); - $this->assertSame(['test1', 'test2'], \iterator_to_array($xliff->extractTranslationKeys())); + self::assertSame(['test1', 'test2'], iterator_to_array($xliff->extractTranslationKeys())); } } From e15b20a28a4858db05b830093e5d7ee6ac8873a8 Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Wed, 2 Mar 2022 16:36:59 +0100 Subject: [PATCH 03/17] Update diagnostics configuration --- .github/workflows/diagnostics.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/diagnostics.yml b/.github/workflows/diagnostics.yml index cd50c20..3e2a4e4 100644 --- a/.github/workflows/diagnostics.yml +++ b/.github/workflows/diagnostics.yml @@ -1,4 +1,4 @@ -name: cyberspectrum/i18n +name: cyberspectrum/i18n-xliff on: push: @@ -15,20 +15,24 @@ jobs: matrix: include: - php: '7.4' - output: '-o github-action -o default' phpcq_install: 'install' + phpcq_flags: '' composer_install: 'update --prefer-lowest' - php: '7.4' - output: '-o github-action -o default' phpcq_install: 'update' + phpcq_flags: '' composer_install: 'update' - php: '8.0' - output: '-o github-action -o default' phpcq_install: 'update' + phpcq_flags: '' composer_install: 'update' - php: '8.1' - output: '-o github-action -o default' phpcq_install: 'update' + phpcq_flags: '' + composer_install: 'update' + - php: '8.2' + phpcq_install: 'update' + phpcq_flags: '--exit-0' composer_install: 'update' steps: @@ -65,13 +69,13 @@ jobs: run: composer ${{ matrix.composer_install }} --prefer-stable --no-interaction --no-progress - name: PHP ${{ matrix.php }} Update phpcq - run: ./vendor/bin/phpcq self-update + run: ./vendor/bin/phpcq self-update --unsigned - name: PHP ${{ matrix.php }} Install phpcq toolchain run: ./vendor/bin/phpcq ${{ matrix.phpcq_install }} -v - name: PHP ${{ matrix.php }} Run tests - run: ./vendor/bin/phpcq run -v ${{ matrix.output }} + run: ./vendor/bin/phpcq run -v -o github-action -o default ${{ matrix.phpcq_flags }} - name: PHP ${{ matrix.php }} Upload build directory to artifact uses: actions/upload-artifact@v2 From 74a69a69cda8454b56590ef6ea967328c6ad5f5a Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Wed, 2 Mar 2022 16:46:43 +0100 Subject: [PATCH 04/17] Drop symfony 3.4 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index af252ef..bc28e2a 100644 --- a/composer.json +++ b/composer.json @@ -25,8 +25,8 @@ "ext-dom": "*", "cyberspectrum/i18n": "dev-fix/phpcq-2 as 1.0.0@dev", "psr/log": "^1.1.4 || ^2.0 || ^3.0", - "symfony/filesystem": "^3.4 || ^4.2 || ^5.0 || ^6.0", - "symfony/finder": "^3.4 || ^4.2 || ^5.0 || ^6.0" + "symfony/filesystem": "^4.4 || ^5.4 || ^6.0", + "symfony/finder": "^4.4 || ^5.4 || ^6.0" }, "require-dev": { "phpcq/runner-bootstrap": "^1.0@dev" From e7e41b46a71eeb3eebfce8c94dd8b1920029d0f2 Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Wed, 2 Mar 2022 17:34:32 +0100 Subject: [PATCH 05/17] Restore compatibility with symfony 4.4 --- src/XliffDictionaryProvider.php | 11 +++++++---- tests/XliffDictionaryProviderTest.php | 13 ++++++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/XliffDictionaryProvider.php b/src/XliffDictionaryProvider.php index 4aafcb4..68ac8cd 100644 --- a/src/XliffDictionaryProvider.php +++ b/src/XliffDictionaryProvider.php @@ -18,6 +18,7 @@ use Psr\Log\LoggerAwareTrait; use Psr\Log\NullLogger; use RuntimeException; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Path; use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; @@ -66,11 +67,13 @@ public function __construct( string $rootDir, string $subDirectoryMask = '{source}-{target}' ) { - $rootDir = Path::canonicalize($rootDir); - if (false === realpath($rootDir) || !is_dir($rootDir)) { + $fileSystem = new Filesystem(); + + $rootDir = $fileSystem->readlink($rootDir, true); + if (null === $rootDir) { throw new InvalidArgumentException('Root directory does not exist or is not a directory.'); } - $this->rootDir = realpath($rootDir); + $this->rootDir = $rootDir; $this->subDirectoryMask = $subDirectoryMask; $this->setLogger(new NullLogger()); } @@ -99,7 +102,7 @@ private function getFileNameFor(string $name, string $sourceLanguage, string $ta . DIRECTORY_SEPARATOR . $name . '.xlf'; } - return $this->rootDir . DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR . $name . '.xlf'; + return $this->rootDir . DIRECTORY_SEPARATOR . $name . '.xlf'; } /** diff --git a/tests/XliffDictionaryProviderTest.php b/tests/XliffDictionaryProviderTest.php index 3102372..4a766e7 100644 --- a/tests/XliffDictionaryProviderTest.php +++ b/tests/XliffDictionaryProviderTest.php @@ -14,7 +14,10 @@ use function iterator_to_array; -/** @covers \CyberSpectrum\I18N\Xliff\XliffDictionaryProvider */ +/** + * @covers \CyberSpectrum\I18N\Xliff\XliffDictionaryProvider + * @SuppressWarnings(PHPMD.TooManyPublicMethods) + */ class XliffDictionaryProviderTest extends TestCase { /** @@ -180,4 +183,12 @@ public function testThrowsForUnwritableRootDir(): void $provider->createDictionary('test1', 'en', 'de'); } + + public function testThrowsForNonExistingRootDir(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Root directory does not exist or is not a directory.'); + + new XliffDictionaryProvider($this->provide() . DIRECTORY_SEPARATOR . 'does-not-exist'); + } } From c2f6a26494868009501e2e238146e5a92166f600 Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Wed, 2 Mar 2022 17:36:15 +0100 Subject: [PATCH 06/17] Remove obsolete travis build state from readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 4bb7993..0d33057 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # i18n-xliff library [![Code Quality Diagnostics](https://github.com/cyberspectrum/i18n-xliff/actions/workflows/diagnostics.yml/badge.svg)](https://github.com/cyberspectrum/i18n-xliff/actions/workflows/diagnostics.yml) -[![Build Status](https://travis-ci.org/cyberspectrum/i18n-xliff.png)](https://travis-ci.org/cyberspectrum/i18n-xliff) [![Latest Version tagged](http://img.shields.io/github/tag/cyberspectrum/i18n-xliff.svg)](https://github.com/cyberspectrum/i18n-xliff/tags) [![Latest Version on Packagist](http://img.shields.io/packagist/v/cyberspectrum/i18n-xliff.svg)](https://packagist.org/packages/cyberspectrum/i18n-xliff) From 339ae9658f3404ca522bc60491360e1a906c2a4d Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Wed, 2 Mar 2022 17:43:40 +0100 Subject: [PATCH 07/17] Make psalm happy again --- src/XliffDictionaryProvider.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/XliffDictionaryProvider.php b/src/XliffDictionaryProvider.php index 68ac8cd..2fb0c52 100644 --- a/src/XliffDictionaryProvider.php +++ b/src/XliffDictionaryProvider.php @@ -19,7 +19,6 @@ use Psr\Log\NullLogger; use RuntimeException; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Filesystem\Path; use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; use Traversable; @@ -30,7 +29,6 @@ use function is_readable; use function is_writable; use function mkdir; -use function realpath; /** * This provides access to the xliff translations in the store. @@ -216,12 +214,20 @@ private function createInformation(SplFileInfo $fileInfo): DictionaryInformation */ private function getFinder(): Iterator { - return Finder::create() + /** + * @var Iterator $iterator + * @psalm-suppress UnnecessaryVarAnnotation + * Symfony 4.4 denotes the iterator as "Iterator|array" + * remove when we drop sf 4.4 + */ + $iterator = Finder::create() ->in($this->rootDir) ->ignoreUnreadableDirs() ->files() ->name('*.xlf') ->getIterator(); + + return $iterator; } /** From 265c7cbe31f86c776e8464042948c18002f579a4 Mon Sep 17 00:00:00 2001 From: Ingolf Steinardt Date: Sat, 23 Mar 2024 13:40:10 +0100 Subject: [PATCH 08/17] Fix composer.json for PHP 8 --- .github/workflows/diagnostics.yml | 20 ++++---------------- composer.json | 12 ++++++------ 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/.github/workflows/diagnostics.yml b/.github/workflows/diagnostics.yml index 3e2a4e4..bef5b78 100644 --- a/.github/workflows/diagnostics.yml +++ b/.github/workflows/diagnostics.yml @@ -14,18 +14,6 @@ jobs: fail-fast: false matrix: include: - - php: '7.4' - phpcq_install: 'install' - phpcq_flags: '' - composer_install: 'update --prefer-lowest' - - php: '7.4' - phpcq_install: 'update' - phpcq_flags: '' - composer_install: 'update' - - php: '8.0' - phpcq_install: 'update' - phpcq_flags: '' - composer_install: 'update' - php: '8.1' phpcq_install: 'update' phpcq_flags: '' @@ -37,7 +25,7 @@ jobs: steps: - name: PHP ${{ matrix.php }} Pull source - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -48,7 +36,7 @@ jobs: php-version: ${{ matrix.php }} - name: PHP ${{ matrix.php }} Cache composer cache directory - uses: actions/cache@v1 + uses: actions/cache@v3 env: cache-name: composer-cache-dir-${{ matrix.php }} with: @@ -56,7 +44,7 @@ jobs: key: ${{ runner.os }}-build-${{ env.cache-name }} - name: PHP ${{ matrix.php }} Cache vendor directory - uses: actions/cache@v1 + uses: actions/cache@v3 env: cache-name: composer-vendor-${{ matrix.php }} with: @@ -78,7 +66,7 @@ jobs: run: ./vendor/bin/phpcq run -v -o github-action -o default ${{ matrix.phpcq_flags }} - name: PHP ${{ matrix.php }} Upload build directory to artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ success() }} || ${{ failure() }} with: name: phpcq-builds-php-${{ matrix.php }} diff --git a/composer.json b/composer.json index bc28e2a..65451ad 100644 --- a/composer.json +++ b/composer.json @@ -21,12 +21,12 @@ "source": "https://github.com/cyberspectrum/i18n-xliff" }, "require": { - "php": "^7.4 || ^8.0", + "php": "^8.1", "ext-dom": "*", - "cyberspectrum/i18n": "dev-fix/phpcq-2 as 1.0.0@dev", - "psr/log": "^1.1.4 || ^2.0 || ^3.0", - "symfony/filesystem": "^4.4 || ^5.4 || ^6.0", - "symfony/finder": "^4.4 || ^5.4 || ^6.0" + "cyberspectrum/i18n": "^1.1@dev", + "psr/log": "^3.0", + "symfony/filesystem": "^5.4 || ^6.0", + "symfony/finder": "^5.4 || ^6.0" }, "require-dev": { "phpcq/runner-bootstrap": "^1.0@dev" @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-fix/phpcq-2": "1.1.x-dev" } } } From 9ec97599ddd0dd81d3cf4481dde667e084bdf2b2 Mon Sep 17 00:00:00 2001 From: Ingolf Steinardt Date: Mon, 25 Mar 2024 17:50:02 +0100 Subject: [PATCH 09/17] Fix diagnostics for minimum dependencies --- .github/workflows/diagnostics.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/diagnostics.yml b/.github/workflows/diagnostics.yml index bef5b78..831df91 100644 --- a/.github/workflows/diagnostics.yml +++ b/.github/workflows/diagnostics.yml @@ -14,13 +14,21 @@ jobs: fail-fast: false matrix: include: + - php: '8.1' + phpcq_install: 'install' + phpcq_flags: '' + composer_install: 'update --prefer-lowest' - php: '8.1' phpcq_install: 'update' phpcq_flags: '' composer_install: 'update' - php: '8.2' phpcq_install: 'update' - phpcq_flags: '--exit-0' + phpcq_flags: '' + composer_install: 'update' + - php: '8.3' + phpcq_install: 'update' + phpcq_flags: '' composer_install: 'update' steps: From b3a0acdb56f0de125a7bf45df04e8270c30e4e37 Mon Sep 17 00:00:00 2001 From: Ingolf Steinardt Date: Mon, 25 Mar 2024 18:08:38 +0100 Subject: [PATCH 10/17] Fix trusted keys --- .phpcq.lock | 2 +- .phpcq.yaml.dist | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.phpcq.lock b/.phpcq.lock index 2f42a09..81c99ce 100644 --- a/.phpcq.lock +++ b/.phpcq.lock @@ -1 +1 @@ -{"plugins":{"phpunit":{"api-version":"1.0.0","version":"1.0.0.0","type":"php-file","url":"https://phpcq.github.io/repository/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.5.16","url":"https://phar.phpunit.de/phpunit-9.5.16.phar","requirements":{"php":{"php":">=7.3","ext-dom":"*","ext-json":"*","ext-libxml":"*","ext-mbstring":"*","ext-xml":"*","ext-xmlwriter":"*"}},"checksum":{"type":"sha-256","value":"342166d3067cb86a4d9620d0a49b9ae4b4bbe25d5d751a0ecfd3ed4e96409b0a"},"signature":"https://phar.phpunit.de/phpunit-9.5.16.phar.asc"}}},"psalm":{"api-version":"1.0.0","version":"1.0.1.0","type":"php-file","url":"https://phpcq.github.io/repository/psalm-1.0.1.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"psalm":"^3.0 || ^4.0"}},"checksum":{"type":"sha-512","value":"fb591fbea784d65ea1b63ba597616c2dd6346958a61a9129aacf612e0deaa14c0de33d9a37cf81b5ed717f09cc3f1280149a0d46576fc838241070176710675f"},"tools":{"psalm":{"version":"4.22.0","url":"https://github.com/vimeo/psalm/releases/download/4.22.0/psalm.phar","requirements":{"php":{"php":"^7.1|^8","ext-SimpleXML":"*","ext-ctype":"*","ext-dom":"*","ext-json":"*","ext-libxml":"*","ext-mbstring":"*","ext-tokenizer":"*"}},"checksum":null,"signature":"https://github.com/vimeo/psalm/releases/download/4.22.0/psalm.phar.asc"}}},"composer-require-checker":{"api-version":"1.0.0","version":"1.0.1.0","type":"php-file","url":"https://phpcq.github.io/repository/composer-require-checker-1.0.1.0.php","signature":null,"requirements":{"php":{"php":"^7.4 || ^8.0"},"tool":{"composer-require-checker":"^3.8"}},"checksum":{"type":"sha-512","value":"5b0fd8cd5e0f5761c53b9d5375b6f6ba50f148468896248f823cc2a48361adfd872556066764b1b544ff51ffd5de60d6f9a75050db00b257d807976ac761bc3a"},"tools":{"composer-require-checker":{"version":"3.8.0","url":"https://github.com/maglnet/ComposerRequireChecker/releases/download/3.8.0/composer-require-checker.phar","requirements":{"php":{"php":"^7.4 || ^8.0","ext-json":"*","ext-phar":"*"}},"checksum":null,"signature":"https://github.com/maglnet/ComposerRequireChecker/releases/download/3.8.0/composer-require-checker.phar.asc"}}},"phpmd":{"api-version":"1.0.0","version":"1.0.1.0","type":"php-file","url":"https://phpcq.github.io/repository/phpmd-1.0.1.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-dom":"*"},"tool":{"phpmd":"^2.6.1"}},"checksum":{"type":"sha-512","value":"88e267b9c36b2edc85e924717606b626e005ac8d97b1f65f5331e2a3b3894dec2cf124f6187541bf759d026477b6d94daacc5d5c81bb09714a68ffabe5698dc5"},"tools":{"phpmd":{"version":"2.11.1","url":"https://github.com/phpmd/phpmd/releases/download/2.11.1/phpmd.phar","requirements":{"php":{"php":">=5.3.9","ext-xml":"*"}},"checksum":null,"signature":null}}},"phpcpd":{"api-version":"1.0.0","version":"1.1.1.0","type":"php-file","url":"https://phpcq.github.io/repository/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"}}},"phploc":{"api-version":"1.0.0","version":"1.0.0.0","type":"php-file","url":"https://phpcq.github.io/repository/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"}}},"phpcs":{"api-version":"1.0.0","version":"1.1.0.0","type":"php-file","url":"https://phpcq.github.io/repository/phpcs-1.1.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":"2737022369da1318cc4e0ea194e8a81019f7b079080d869aab878b7486052fdbe68fee3f28131f35573226def1aabd4bd005e038ee7b767c137b1107c1492a83"},"tools":{"phpcs":{"version":"3.6.2","url":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcs.phar","requirements":{"php":{"php":">=5.4.0","ext-tokenizer":"*","ext-xmlwriter":"*","ext-simplexml":"*"}},"checksum":null,"signature":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcs.phar.asc"},"phpcbf":{"version":"3.6.2","url":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcbf.phar","requirements":{"php":{"php":">=5.4.0","ext-tokenizer":"*","ext-xmlwriter":"*","ext-simplexml":"*"}},"checksum":null,"signature":"https://github.com/squizlabs/PHP_CodeSniffer/releases/download/3.6.2/phpcbf.phar.asc"}}},"composer-normalize":{"api-version":"1.0.0","version":"1.1.0.0","type":"php-file","url":"https://phpcq.github.io/repository/composer-normalize-1.1.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-json":"*"},"tool":{"composer-normalize":"^2.1"}},"checksum":{"type":"sha-512","value":"d59d3557cb20630734878a9115df5dd32d5aff815e5b15be36f6fb5d6e9d83dd36efd84215ab6529edcc924f600946f739a0d9e67723deff95c88346ab502498"},"tools":{"composer-normalize":{"version":"2.23.1","url":"https://github.com/ergebnis/composer-normalize/releases/download/2.23.1/composer-normalize.phar","requirements":{"php":{"php":"^7.4 || ^8.0"}},"checksum":null,"signature":"https://github.com/ergebnis/composer-normalize/releases/download/2.23.1/composer-normalize.phar.asc"}}}},"tools":[]} \ No newline at end of file +{"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.18","url":"https://phar.phpunit.de/phpunit-9.6.18.phar","requirements":{"php":{"php":">=7.3","ext-dom":"*","ext-json":"*","ext-libxml":"*","ext-mbstring":"*","ext-xml":"*","ext-xmlwriter":"*"}},"checksum":{"type":"sha-256","value":"fc3729afdbab93cbf9f662de730bcc2f936bd9255bb08c6c53d41b9b0a30ec62"},"signature":"https://phar.phpunit.de/phpunit-9.6.18.phar.asc"}},"composerLock":null},"psalm":{"api-version":"1.0.0","version":"1.2.0.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/psalm/psalm-1.2.0.0.php","signature":null,"requirements":{"php":{"php":"^7.4 || ^8.0","ext-dom":"*"},"tool":{"psalm":"^3.0 || ^4.0 || ^5.0"}},"checksum":{"type":"sha-512","value":"4a550c9226d7bca582d7c10bd87cce01190c96398936b1613421640c83df62ed1c6e0d44c1b39635414ea8cf4a892a6458d27590793238add24e7cb5547e6ffd"},"tools":{"psalm":{"version":"5.23.1","url":"https://github.com/vimeo/psalm/releases/download/5.23.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.23.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":"3.8.0","url":"https://github.com/maglnet/ComposerRequireChecker/releases/download/3.8.0/composer-require-checker.phar","requirements":{"php":{"php":"^7.4 || ^8.0","ext-json":"*","ext-phar":"*"}},"checksum":null,"signature":"https://github.com/maglnet/ComposerRequireChecker/releases/download/3.8.0/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.1.1.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/phpcs/phpcs-1.1.1.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":"2737022369da1318cc4e0ea194e8a81019f7b079080d869aab878b7486052fdbe68fee3f28131f35573226def1aabd4bd005e038ee7b767c137b1107c1492a83"},"tools":{"phpcs":{"version":"3.9.0","url":"https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/download/3.9.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.9.0/phpcs.phar.asc"},"phpcbf":{"version":"3.9.0","url":"https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/download/3.9.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.9.0/phpcbf.phar.asc"}},"composerLock":null},"composer-normalize":{"api-version":"1.0.0","version":"1.1.0.0","type":"php-file","url":"https://phpcq.github.io/repository/plugin/composer-normalize/composer-normalize-1.1.0.0.php","signature":null,"requirements":{"php":{"php":"^7.3 || ^8.0","ext-json":"*"},"tool":{"composer-normalize":"^2.1"}},"checksum":{"type":"sha-512","value":"d59d3557cb20630734878a9115df5dd32d5aff815e5b15be36f6fb5d6e9d83dd36efd84215ab6529edcc924f600946f739a0d9e67723deff95c88346ab502498"},"tools":{"composer-normalize":{"version":"2.42.0","url":"https://github.com/ergebnis/composer-normalize/releases/download/2.42.0/composer-normalize.phar","requirements":{"php":{"php":"~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0","ext-json":"*"}},"checksum":null,"signature":"https://github.com/ergebnis/composer-normalize/releases/download/2.42.0/composer-normalize.phar.asc"}},"composerLock":null}},"tools":[]} \ No newline at end of file diff --git a/.phpcq.yaml.dist b/.phpcq.yaml.dist index f9f93bf..0dc2d5c 100644 --- a/.phpcq.yaml.dist +++ b/.phpcq.yaml.dist @@ -51,10 +51,12 @@ phpcq: - D2CCAC42F6295E7D # PHP_CodeSniffer - 31C7E470E2138192 + - 5E6DDE998AB73B8E # Composer normalize - C00543248C87FB13 # phpmd - 0F9684B8B16B7AB0 + - 9093F8B32E4815AA # composer-require-checker - 033E5F8D801A2F8D From c4e9fec050c33469f0cb27f336652f241cfd6131 Mon Sep 17 00:00:00 2001 From: Ingolf Steinardt Date: Mon, 25 Mar 2024 19:00:34 +0100 Subject: [PATCH 11/17] Fix composer dependencies --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 65451ad..493def6 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "php": "^8.1", "ext-dom": "*", "cyberspectrum/i18n": "^1.1@dev", - "psr/log": "^3.0", + "psr/log": "^2.0 || ^3.0", "symfony/filesystem": "^5.4 || ^6.0", "symfony/finder": "^5.4 || ^6.0" }, From a65a92fbeb04cf57aa9e6aa54377063d94dac3ba Mon Sep 17 00:00:00 2001 From: David Molineus Date: Tue, 16 Apr 2024 15:18:26 +0200 Subject: [PATCH 12/17] Allow symfony components in version 7 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 493def6..541d50c 100644 --- a/composer.json +++ b/composer.json @@ -25,8 +25,8 @@ "ext-dom": "*", "cyberspectrum/i18n": "^1.1@dev", "psr/log": "^2.0 || ^3.0", - "symfony/filesystem": "^5.4 || ^6.0", - "symfony/finder": "^5.4 || ^6.0" + "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", + "symfony/finder": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { "phpcq/runner-bootstrap": "^1.0@dev" From 080ed271462e4d0662f0acc4480e505cab1f8461 Mon Sep 17 00:00:00 2001 From: David Molineus Date: Tue, 16 Apr 2024 15:23:29 +0200 Subject: [PATCH 13/17] Fix buffering --- src/WritableXliffDictionary.php | 2 ++ tests/WritableXliffDictionaryTest.php | 25 ++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/WritableXliffDictionary.php b/src/WritableXliffDictionary.php index f0eaa55..fe7e464 100644 --- a/src/WritableXliffDictionary.php +++ b/src/WritableXliffDictionary.php @@ -117,6 +117,8 @@ public function beginBuffering(): void if ($this->buffering) { throw new RuntimeException('Already buffering.'); } + + $this->buffering = true; } /** diff --git a/tests/WritableXliffDictionaryTest.php b/tests/WritableXliffDictionaryTest.php index b082bee..b8911c9 100644 --- a/tests/WritableXliffDictionaryTest.php +++ b/tests/WritableXliffDictionaryTest.php @@ -27,11 +27,11 @@ public function testInstantiation(): void self::assertSame('de', $dictionary->getTargetLanguage()); self::assertSame( ['test-string-with-only-source', 'test-string-with-source-and-target'], - iterator_to_array($dictionary->keys()) + iterator_to_array($dictionary->keys()), ); self::assertInstanceOf( XliffTranslationValue::class, - $value = $dictionary->get('test-string-with-only-source') + $value = $dictionary->get('test-string-with-only-source'), ); self::assertSame('test-string-with-only-source', $value->getKey()); self::assertSame('The source value', $value->getSource()); @@ -41,7 +41,7 @@ public function testInstantiation(): void self::assertInstanceOf( XliffTranslationValue::class, - $value = $dictionary->get('test-string-with-source-and-target') + $value = $dictionary->get('test-string-with-source-and-target'), ); self::assertSame('test-string-with-source-and-target', $value->getKey()); self::assertSame('The source value', $value->getSource()); @@ -133,4 +133,23 @@ public function testWritingThrowsForUnknown(): void $dictionary->getWritable('unknown-key'); } + + public function testBuffering(): void + { + $dictionary = new WritableXliffDictionary($this->getTempFile()); + $dictionary->beginBuffering(); + self::assertTrue($dictionary->isBuffering()); + } + + public function commitBuffering(): void + { + $dictionary = new WritableXliffDictionary($this->getTempFile()); + $dictionary->beginBuffering(); + self::assertTrue($dictionary->isBuffering()); + + $dictionary->add('test'); + $dictionary->commitBuffer(); + + self::assertFalse($dictionary->isBuffering()); + } } From 774ed38f8fde837676cead7db795c6ee230e1b5d Mon Sep 17 00:00:00 2001 From: David Molineus Date: Tue, 16 Apr 2024 15:30:23 +0200 Subject: [PATCH 14/17] Do not use relative callables Do not use parent in a callable as it got deprecated in PHP 8.2, see https://www.php.net/manual/en/migration82.deprecated.php --- src/Xml/XmlElement.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Xml/XmlElement.php b/src/Xml/XmlElement.php index f3f2e44..66d9b4c 100644 --- a/src/Xml/XmlElement.php +++ b/src/Xml/XmlElement.php @@ -40,11 +40,11 @@ public function setAttributeNS($namespace, $qualifiedName, $value): void $namespace === XliffFile::XLIFF_NS && $this->ownerDocument->isDefaultNamespace(XliffFile::XLIFF_NS) ) { - call_user_func_array(['parent', 'setAttribute'], array_slice(func_get_args(), 1)); + parent::setAttribute($qualifiedName, $value); return; } - call_user_func_array(['parent', 'setAttributeNS'], func_get_args()); + parent::setAttributeNS($namespace, $qualifiedName, $value); } /** @@ -69,11 +69,9 @@ public function getAttributeNS($namespace, $localName): string $namespace === XliffFile::XLIFF_NS && $this->ownerDocument->isDefaultNamespace(XliffFile::XLIFF_NS) ) { - /** @psalm-suppress MixedReturnStatement */ - return call_user_func_array(['parent', 'getAttribute'], array_slice(func_get_args(), 1)); + return parent::getAttribute($localName); } - /** @psalm-suppress MixedReturnStatement */ - return call_user_func_array(['parent', 'getAttributeNS'], func_get_args()); + return parent::getAttributeNS($namespace, $localName); } } From e0d63d6cc3202af3f8cdcdfb5264bed271dd41ac Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Wed, 17 Apr 2024 19:23:14 +0200 Subject: [PATCH 15/17] Fix further issues detected by psalm --- src/WritableXliffDictionary.php | 4 ++-- src/XliffDictionary.php | 2 +- src/Xml/XliffFile.php | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/WritableXliffDictionary.php b/src/WritableXliffDictionary.php index f0eaa55..49d0ab8 100644 --- a/src/WritableXliffDictionary.php +++ b/src/WritableXliffDictionary.php @@ -57,10 +57,10 @@ public function __construct(string $filename, ?string $sourceLanguage = null, ?s } if (!file_exists($filename)) { - if ($sourceLanguage) { + if ((bool) $sourceLanguage) { $this->setSourceLanguage($sourceLanguage); } - if ($targetLanguage) { + if ((bool) $targetLanguage) { $this->setTargetLanguage($targetLanguage); } $this->markChanged(); diff --git a/src/XliffDictionary.php b/src/XliffDictionary.php index 8953548..8b1b934 100644 --- a/src/XliffDictionary.php +++ b/src/XliffDictionary.php @@ -28,7 +28,7 @@ class XliffDictionary implements DictionaryInterface public function __construct(?string $filename = null) { $this->xliff = new XliffFile(); - if ($filename && is_readable($filename)) { + if ((bool) $filename && is_readable($filename)) { $this->xliff->load($filename); } } diff --git a/src/Xml/XliffFile.php b/src/Xml/XliffFile.php index db4e0d0..a75fcad 100644 --- a/src/Xml/XliffFile.php +++ b/src/Xml/XliffFile.php @@ -17,9 +17,11 @@ use RuntimeException; /** - * This is an xliff implementation. + * This is a xliff implementation. * * @internal Only to be used within this abstraction. + * + * @psalm-suppress PropertyNotSetInConstructor The properties are inherited from the parent class and set by loading. */ final class XliffFile extends DOMDocument { @@ -200,7 +202,7 @@ public function searchTranslationUnit(string $identifier): ?XmlElement } if ( - $this->documentElement->isDefaultNamespace(self::XLIFF_NS) + $this->documentElement?->isDefaultNamespace(self::XLIFF_NS) && $transUnit = $this->getXPathFirstItem( '/xlf:xliff/xlf:file/xlf:body/xlf:trans-unit[@id=\'' . $identifier . '\']' ) From 497c3130dc4afbbb834479c252b1ada666d6507a Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Mon, 22 Apr 2024 16:21:46 +0200 Subject: [PATCH 16/17] Do not set a null logger by default --- src/XliffDictionaryProvider.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/XliffDictionaryProvider.php b/src/XliffDictionaryProvider.php index 2fb0c52..602ed43 100644 --- a/src/XliffDictionaryProvider.php +++ b/src/XliffDictionaryProvider.php @@ -16,7 +16,6 @@ use Iterator; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; -use Psr\Log\NullLogger; use RuntimeException; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; @@ -73,7 +72,6 @@ public function __construct( } $this->rootDir = $rootDir; $this->subDirectoryMask = $subDirectoryMask; - $this->setLogger(new NullLogger()); } public function getAvailableDictionaries(): Traversable From a159383b1394de5f420526c2e252c7acaa061172 Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Wed, 24 Apr 2024 15:35:00 +0200 Subject: [PATCH 17/17] Bump gh actions and update artifacts/cache keys --- .github/workflows/diagnostics.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/diagnostics.yml b/.github/workflows/diagnostics.yml index 831df91..224fd95 100644 --- a/.github/workflows/diagnostics.yml +++ b/.github/workflows/diagnostics.yml @@ -33,7 +33,7 @@ jobs: steps: - name: PHP ${{ matrix.php }} Pull source - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -44,15 +44,15 @@ jobs: php-version: ${{ matrix.php }} - name: PHP ${{ matrix.php }} Cache composer cache directory - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: composer-cache-dir-${{ matrix.php }} with: path: ~/.cache/composer - key: ${{ runner.os }}-build-${{ env.cache-name }} + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ matrix.phpcq_install }}-${{ matrix.phpcq_flags }}-${{ matrix.composer_install }} - name: PHP ${{ matrix.php }} Cache vendor directory - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: composer-vendor-${{ matrix.php }} with: @@ -74,8 +74,8 @@ jobs: run: ./vendor/bin/phpcq run -v -o github-action -o default ${{ matrix.phpcq_flags }} - name: PHP ${{ matrix.php }} Upload build directory to artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ success() }} || ${{ failure() }} with: - name: phpcq-builds-php-${{ matrix.php }} + name: phpcq-builds-php-${{ matrix.php }}-${{ matrix.phpcq_install }}-${{ matrix.phpcq_flags }}-${{ matrix.composer_install }} path: .phpcq/build/